Skip to content

Commit

Permalink
Stop generating MoarVM if_o and unless_o ops
Browse files Browse the repository at this point in the history
These ops, along with istrue and isfalse, behave according to the
object's boolification protocol configuration and may result in a
method call. Said method call needs to be performed via the new
dispatch mechanism.

For now, generate istrue + if_i/unless_i; the istrue will later become a
dispatch op, so factor out emitting it in preparation for that.
  • Loading branch information
jnthn committed Jul 9, 2021
1 parent 479421d commit b76786d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 25 deletions.
46 changes: 32 additions & 14 deletions src/vm/moar/QAST/QASTOperationsMAST.nqp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ my int $MVM_operand_uint16 := ($MVM_reg_uint16 * 8);
my int $MVM_operand_uint32 := ($MVM_reg_uint32 * 8);
my int $MVM_operand_uint64 := ($MVM_reg_uint64 * 8);

my %core_op_generators := MAST::Ops.WHO<%generators>;
my &op_decont := %core_op_generators<decont>;
my &op_goto := %core_op_generators<goto>;
my &op_null := %core_op_generators<null>;
Expand Down Expand Up @@ -691,7 +690,10 @@ my $chain_gen := sub ($qastcomp, $op) {
$regalloc.release_register($acomp.result_reg, $MVM_reg_obj);

if @clist {
%core_op_generators{'unless_o'}($res_reg, $endlabel);
my $boolification_reg := $regalloc.fresh_register($MVM_reg_int64);
emit_object_boolify($boolification_reg, $res_reg);
%core_op_generators{'unless_i'}($boolification_reg, $endlabel);
$regalloc.release_register($boolification_reg, $MVM_reg_int64);
$cqast := nqp::pop(@clist);
$arg_idx := get_arg_idx($cqast);
$acomp := $bcomp;
Expand Down Expand Up @@ -751,9 +753,8 @@ for <if unless with without> -> $op_name {
$op[0]));
}
}
elsif nqp::istype($op[0], QAST::Var)
&& $op[0].scope eq 'lexicalref'
&& (!$*WANT || $operands == 3) {
elsif nqp::istype($op[0], QAST::Var) && $op[0].scope eq 'lexicalref'
&& (!$*WANT || $operands == 3) {
# lexical refs are expensive; try to coerce them to something cheap
my $spec := nqp::objprimspec($op[0].returns);
@comp_ops[0] := $qastcomp.as_mast(:want(
Expand Down Expand Up @@ -838,24 +839,34 @@ for <if unless with without> -> $op_name {

# Emit the jump.
if nqp::unbox_i(@comp_ops[0].result_kind) == $MVM_reg_obj {
# First decontainerize the object.
my $decont_reg := $regalloc.fresh_register($MVM_reg_obj);
op_decont($decont_reg, @comp_ops[0].result_reg);

# If it's a `with` or `without`, need to call defined.
# TODO emit dispatch op
if $is_withy {
my $method_reg := $regalloc.fresh_register($MVM_reg_obj);
%core_op_generators{'findmeth'}($method_reg, $decont_reg, 'defined');
MAST::Call.new( :target($method_reg), :result($decont_reg), :flags([$Arg::obj]), $decont_reg);
$regalloc.release_register($method_reg, $MVM_reg_obj);
}

# Boolify the object
my $boolification_reg := $regalloc.fresh_register($MVM_reg_int64);
emit_object_boolify($boolification_reg, $decont_reg);
$regalloc.release_register($decont_reg, $MVM_reg_obj);

# Generate the branch instruction.
%core_op_generators{
# the conditional routines are reversed on purpose
$op_name eq 'if' || $op_name eq 'with'
?? 'unless_o' !! 'if_o'
?? 'unless_i' !! 'if_i'
}(
$decont_reg,
$boolification_reg,
($operands == 3 ?? $else_lbl !! $end_lbl)
);
$regalloc.release_register($decont_reg, $MVM_reg_obj);
$regalloc.release_register($boolification_reg, $MVM_reg_int64);
}
elsif @Full-width-coerce-to[@comp_ops[0].result_kind] -> $coerce-kind {
# workaround for coercion unconditionally releasing the source register while we still need it later on
Expand Down Expand Up @@ -983,15 +994,15 @@ QAST::MASTOperations.add_core_op('xor', -> $qastcomp, $op {
my $apost := $qastcomp.as_mast(nqp::shift(@comp_ops), :want($MVM_reg_obj));
op_set($res_reg, $apost.result_reg);
op_decont($d, $apost.result_reg);
%core_op_generators{'istrue'}($t, $d);
emit_object_boolify($t, $d);
$*REGALLOC.release_register($apost.result_reg, $MVM_reg_obj);

my $have_middle_child := 1;
my $bpost;
while $have_middle_child {
$bpost := $qastcomp.as_mast(nqp::shift(@comp_ops), :want($MVM_reg_obj));
op_decont($d, $bpost.result_reg);
%core_op_generators{'istrue'}($u, $d);
emit_object_boolify($u, $d);

my $jumplabel := MAST::Label.new();
%core_op_generators{'unless_i'}($t, $jumplabel);
Expand Down Expand Up @@ -1094,16 +1105,20 @@ sub loop_body($res_reg, $repness, $cond_temp, $redo_lbl, $test_lbl, @children, $
if $operands != 2 && $operands != 3;

if @comp_ops[0].result_kind == $MVM_reg_obj {
# Decontainerize it and perform boolean conversion, then test that.
my $decont_reg := $regalloc.fresh_register($MVM_reg_obj);
op_decont($decont_reg, @comp_ops[0].result_reg);
my $boolification_reg := $regalloc.fresh_register($MVM_reg_int64);
emit_object_boolify($boolification_reg, $decont_reg);
$regalloc.release_register($decont_reg, $MVM_reg_obj);
%core_op_generators{
# the conditional routines are reversed on purpose
$op_name eq 'while' ?? 'unless_o' !! 'if_o'
$op_name eq 'while' ?? 'unless_i' !! 'if_i'
}(
$decont_reg,
$boolification_reg,
$done_lbl
);
$regalloc.release_register($decont_reg, $MVM_reg_obj);
$regalloc.release_register($boolification_reg, $MVM_reg_int64);
}
elsif @Full-width-coerce-to[@comp_ops[0].result_kind]
-> $coerce-kind {
Expand Down Expand Up @@ -1266,7 +1281,10 @@ for ('', 'repeat_') -> $repness {
sub for_loop_body($lbl_next, $iter_tmp, $lbl_done, @operands, $regalloc, $lbl_redo, $block_res, @val_temps) {
# Emit loop test.
$*MAST_FRAME.add-label($lbl_next);
%core_op_generators{'unless_o'}($iter_tmp, $lbl_done);
my $boolification_reg := $regalloc.fresh_register($MVM_reg_int64);
emit_object_boolify($boolification_reg, $iter_tmp);
%core_op_generators{'unless_i'}($boolification_reg, $lbl_done);
$regalloc.release_register($boolification_reg, $MVM_reg_int64);

# Fetch values into temporaries (on the stack ain't enough in case
# of redo).
Expand Down
41 changes: 30 additions & 11 deletions src/vm/moar/QAST/QASTRegexCompilerMAST.nqp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ my @Condition-op-kinds := nqp::list(
'if_i', 'if_i', # $MVM_reg_int16, $MVM_reg_int32
'if_i', 'if_n', # $MVM_reg_int64, $MVM_reg_num32
'if_n', 'if_s', # $MVM_reg_num64, $MVM_reg_str
'if_o', # $MVM_reg_obj
nqp::null, # $MVM_reg_obj requires special generation
nqp::null, nqp::null, nqp::null, nqp::null,
nqp::null, nqp::null, nqp::null, nqp::null,
'if_i', # $MVM_reg_uint8
Expand All @@ -35,7 +35,7 @@ my @Negated-condition-op-kinds := nqp::list(
'unless_i', 'unless_i', # $MVM_reg_int16, $MVM_reg_int32
'unless_i', 'unless_n', # $MVM_reg_int64, $MVM_reg_num32
'unless_n', 'unless_s', # $MVM_reg_num64, $MVM_reg_str
'unless_o', # $MVM_reg_obj,
nqp::null, # $MVM_reg_obj requires special generation
nqp::null, nqp::null, nqp::null, nqp::null,
nqp::null, nqp::null, nqp::null, nqp::null,
'unless_i', 'unless_i', # $MVM_reg_uint8, $MVM_reg_uint16
Expand All @@ -52,6 +52,14 @@ my @Full-width-coerce-to := nqp::list( # 0 means we don't need any coersion
$MVM_reg_int64, $MVM_reg_int64, # $MVM_reg_uint32, $MVM_reg_uint64
);

my %core_op_generators := MAST::Ops.WHO<%generators>;

# Emits an instruction to boolify an object. The result register should
# be an int64, the object should have already been decontainerized.
sub emit_object_boolify($result_reg, $object_reg) {
%core_op_generators<istrue>($result_reg, $object_reg);
}

class QAST::MASTRegexCompiler {
# The compiler we're working against.
has $!qastcomp;
Expand Down Expand Up @@ -242,7 +250,8 @@ class QAST::MASTRegexCompiler {
my $cutlabel := label();
op('isnull', $i0, $cstack);
op('if_i', $i0, $jumplabel);
op('unless_o', $cstack, $jumplabel);
emit_object_boolify($i0, $cstack);
op('unless_i', $i0, $jumplabel);
op('elems', $i18, $bstack);
op('le_i', $i0, $i18, $zero);
op('if_i', $i0, $cutlabel);
Expand Down Expand Up @@ -707,15 +716,25 @@ class QAST::MASTRegexCompiler {
op('bindattr_i', %!reg<cur>, %!reg<curclass>, sval('$!pos'), %!reg<pos>, ival(-1));
op('bindlex', $*BLOCK.resolve_lexical(''), %!reg<cur>);
my $cmast := $!qastcomp.as_mast($node[0]);
$!regalloc.release_register($cmast.result_reg, $cmast.result_kind);
my $cndop := $node.negate # the negation meaning is reversed for the op
?? @Condition-op-kinds[ $cmast.result_kind]
!! @Negated-condition-op-kinds[$cmast.result_kind];
if $node.subtype eq 'zerowidth' && ! nqp::isnull($cndop) {
op('decont', $cmast.result_reg, $cmast.result_reg)
if $cmast.result_kind == $MVM_reg_obj;
op($cndop, $cmast.result_reg, %!reg<fail>);
if $node.subtype eq 'zerowidth' {
my int $result_kind := $cmast.result_kind;
if $result_kind == $MVM_reg_obj {
op('decont', $cmast.result_reg, $cmast.result_reg);
my $boolification_reg := $!regalloc.fresh_register($MVM_reg_int64);
emit_object_boolify($boolification_reg, $cmast.result_reg);
op($node.negate ?? 'if_i' !! 'unless_i', $boolification_reg, %!reg<fail>);
$!regalloc.release_register($boolification_reg, $MVM_reg_int64);
}
else {
my $cndop := $node.negate # the negation meaning is reversed for the op
?? @Condition-op-kinds[ $result_kind]
!! @Negated-condition-op-kinds[$result_kind];
unless nqp::isnull($cndop) {
op($cndop, $cmast.result_reg, %!reg<fail>);
}
}
}
$!regalloc.release_register($cmast.result_reg, $cmast.result_kind);
}

method dynquant($node) {
Expand Down

0 comments on commit b76786d

Please sign in to comment.