Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[dotnet] Very first cut of auto-box/auto-unbox bits in PAST2DNST.pm. …
…This means that we can start switching quite a few ops to work with native types, then use the natives when we have them to hand, avoiding epic boxing/unboxing. Switch a few equality ops over; code-gen looks rather better.
  • Loading branch information
jnthn committed Dec 4, 2010
1 parent a5559d5 commit f0d70f0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 27 deletions.
62 changes: 53 additions & 9 deletions dotnet/compiler/PAST2DNSTCompiler.pm
Expand Up @@ -3,6 +3,18 @@
# and more of PAST.
class PAST2DNSTCompiler;

# Set up a hash of operator signatures. Only needed for those that do not
# return and take just RakudoObject instances. First type is return type,
# following ones are argument types.
our %nqp_op_sigs;
INIT {
%nqp_op_sigs := pir::new__pS('Hash');
%nqp_op_sigs<equal_nums> := ('int', 'num', 'num');
%nqp_op_sigs<equal_ints> := ('int', 'int', 'int');
%nqp_op_sigs<equal_strs> := ('int', 'str', 'str');
%nqp_op_sigs<logical_not_int> := ('int', 'int');
}

# Entry point for the compiler.
method compile(PAST::Node $node) {
# This tracks the unique IDs we generate in this compilation unit.
Expand Down Expand Up @@ -31,6 +43,10 @@ method compile(PAST::Node $node) {
# Current namespace path.
my @*CURRENT_NS;

# The current type context, e.g. what result type the thing further
# up in the tree is expecting.
my $*TYPE_CONTEXT := 'obj';

# Compile the node; ensure it is an immediate block.
$node.blocktype('immediate');
my $main_block_call := dnst_for($node);
Expand Down Expand Up @@ -490,7 +506,6 @@ our multi sub dnst_for(PAST::Block $block) {
}

# Compiles a bunch of parameter nodes down to a signature.
# XXX Doesn't handle default values just yet.
sub compile_signature(@params) {
# Go through each of the parameters and compile them.
my $params := DNST::ArrayLiteral.new( :type('Parameter') );
Expand Down Expand Up @@ -1701,7 +1716,8 @@ sub vm_type_for($type) {
$type eq 'num' ?? 'double' !!
$type eq 'str' ?? 'string' !!
$type eq 'int' ?? 'int' !!
pir::die("Don't know VM type for $type")
$type eq 'obj' ?? 'RakudoObject' !!
pir::die("Don't know VM type for $type")
}

sub plus($l, $r, $type?) {
Expand Down Expand Up @@ -1814,16 +1830,45 @@ sub val($val) {
!! dnst_for(PAST::Val.new( :value($val) ))
}

sub emit_op($name, :$type, *@args) {
sub emit_op($name, *@args) {
# See if we have any info on this op's siggy.
my $sig := %nqp_op_sigs{$name};
my $type := 'obj';
if pir::defined($sig) {
$type := $sig[0];
}

# Compile the args.
my @dnst_args;
my $i := 1;
for @args {
@dnst_args.push(dnst_for($_))
# Set the type context that is desired.
my $*TYPE_CONTEXT := pir::defined($sig) ?? $sig[$i] !! 'obj';
my $arg_dnst := dnst_for($_);

# We may need to auto-unbox it if we don't have the desired type
# of thing.
if $*TYPE_CONTEXT ne 'obj' {
unless ($arg_dnst ~~ DNST::MethodCall || $arg_dnst ~~ DNST::Call)
&& $arg_dnst.type eq vm_type_for($*TYPE_CONTEXT) {
$arg_dnst := unbox($*TYPE_CONTEXT, $arg_dnst);
}
}

@dnst_args.push($arg_dnst);
}
DNST::MethodCall.new(

# Build op call.
my $call := DNST::MethodCall.new(
:on('Ops'), :name($name),
:type($type || 'RakudoObject'),
:type(vm_type_for($type)),
'TC', |@dnst_args
)
);

# We may need to auto-box it.
$type ne $*TYPE_CONTEXT && $*TYPE_CONTEXT eq 'obj' ??
box($type, $call) !!
$call
}

sub emit_call($on, $name, $type, *@args) {
Expand Down Expand Up @@ -1862,8 +1907,7 @@ sub returns_array($expr, *@result_slots) {
lit(~($i / 2))))
!! emit_op('lllist_get_at_pos',
DNST::Local.new(:name($tmp.name)),
lit(~($i / 2)),
:type('RakudoObject'))
lit(~($i / 2)))
));
$i := $i + 2;
};
Expand Down
24 changes: 9 additions & 15 deletions dotnet/runtime/Runtime/Ops/Comparison.cs
Expand Up @@ -16,43 +16,37 @@ public static partial class Ops
/// <summary>
/// Compares two floating point numbers for equality.
/// </summary>
/// <param name="TC"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="ResultType"></param>
/// <returns></returns>
public static RakudoObject equal_nums(ThreadContext TC, RakudoObject x, RakudoObject y)
public static int equal_nums(ThreadContext TC, double x, double y)
{
return Ops.box_int(TC,
(Ops.unbox_num(TC, x) == Ops.unbox_num(TC, y) ? 1 : 0),
TC.DefaultBoolBoxType);
return x == y ? 1 : 0;
}

/// <summary>
/// Compares two integers for equality.
/// </summary>
/// <param name="TC"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="ResultType"></param>
/// <returns></returns>
public static RakudoObject equal_ints(ThreadContext TC, RakudoObject x, RakudoObject y)
public static int equal_ints(ThreadContext TC, int x, int y)
{
return Ops.box_int(TC,
(Ops.unbox_int(TC, x) == Ops.unbox_int(TC, y) ? 1 : 0),
TC.DefaultBoolBoxType);
return x == y ? 1 : 0;
}

/// <summary>
/// Compares two strings for equality.
/// </summary>
/// <param name="TC"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="ResultType"></param>
/// <returns></returns>
public static RakudoObject equal_strs(ThreadContext TC, RakudoObject x, RakudoObject y)
public static int equal_strs(ThreadContext TC, string x, string y)
{
return Ops.box_int(TC,
(Ops.unbox_str(TC, x) == Ops.unbox_str(TC, y) ? 1 : 0),
TC.DefaultBoolBoxType);
return x == y ? 1 : 0;
}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions dotnet/runtime/Runtime/Ops/Primitive.cs
Expand Up @@ -17,12 +17,12 @@ public static partial class Ops
/// <summary>
/// Logical not.
/// </summary>
/// <param name="TC"></param>
/// <param name="x"></param>
/// <param name="ResultType"></param>
/// <returns></returns>
public static RakudoObject logical_not_int(ThreadContext TC, RakudoObject x)
public static int logical_not_int(ThreadContext TC, int x)
{
return Ops.box_int(TC, Ops.unbox_int(TC, x) == 0 ? 1 : 0, TC.DefaultBoolBoxType);
return x == 0 ? 1 : 0;
}

/// <summary>
Expand Down

0 comments on commit f0d70f0

Please sign in to comment.