/*
** cmp.ops
*/

VERSION = PARROT_VERSION;

=head1 NAME

cmp.ops - Register Comparison Ops

=cut

=head1 DESCRIPTION

Operations that compare two registers against each other.
Some of these operations affect control flow directly; others
do not.

=cut

###############################################################################

=head2 Flow control comparison operators

These operators branch based on the relationship between
their operands.

=over 4

=cut

########################################

=item B<eq>(in INT, in INT, inconst INT)

=item B<eq>(in NUM, in NUM, inconst INT)

=item B<eq>(in STR, in STR, inconst INT)

=item B<eq>(in PMC, in PMC, inconst INT)

=item B<eq>(in PMC, in INT, inconst INT)

Branch if $1 is equal to $2.

=cut

inline op eq(in INT, in INT, inconst INT) {
  if ($1 == $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

inline op eq(in NUM, in NUM, inconst INT) {
  if ($1 == $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op eq(in STR, in STR, inconst INT) {
  if (string_compare(interpreter, $1, $2) == 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op eq (in PMC, in PMC, inconst INT) {
  if ($1->vtable->is_equal(interpreter, $1, $2)) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op eq (in PMC, in INT, inconst INT) {
  if ($1->vtable->get_integer(interpreter, $1) == $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

########################################

=item B<ne>(in INT, in INT, inconst INT)

=item B<ne>(in NUM, in NUM, inconst INT)

=item B<ne>(in STR, in STR, inconst INT)

=item B<ne>(in PMC, in PMC, inconst INT)

Branch if $1 is not equal to $2.

=cut

inline op ne(in INT, in INT, inconst INT) {
  if ($1 != $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

inline op ne(in NUM, in NUM, inconst INT) {
  if ($1 != $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op ne(in STR, in STR, inconst INT) {
  if (string_compare(interpreter, $1, $2) != 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op ne(in PMC, in PMC, inconst INT) {
  if (! $1->vtable->is_equal(interpreter, $1, $2)) {
    goto OFFSET($3);
  }
  goto NEXT();
}

########################################

=item B<lt>(in INT, in INT, inconst INT)

=item B<lt>(in NUM, in NUM, inconst INT)

=item B<lt>(in STR, in STR, inconst INT)

=item B<lt>(in PMC, in PMC, inconst INT)

=item B<lt>(in PMC, in INT, inconst INT)

Branch if $1 is less than $2.

=cut

inline op lt(in INT, in INT, inconst INT) {
  if ($1 < $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

inline op lt(in NUM, in NUM, inconst INT) {
  if ($1 < $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op lt(in STR, in STR, inconst INT) {
  if (string_compare(interpreter, $1, $2) < 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op lt (in PMC, in PMC, inconst INT) {
  if ($1->vtable->cmp(interpreter, $1, $2) < 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op lt (in PMC, in INT, inconst INT) {
  if ($1->vtable->get_integer(interpreter, $1) < $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

########################################

=item B<le>(in INT, in INT, inconst INT)

=item B<le>(in NUM, in NUM, inconst INT)

=item B<le>(in STR, in STR, inconst INT)

=item B<le>(in PMC, in PMC, inconst INT)

=item B<le>(in PMC, in INT, inconst INT)

Branch if $1 is less than or equal to $2.

=cut

inline op le(in INT, in INT, inconst INT) {
  if ($1 <= $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

inline op le(in NUM, in NUM, inconst INT) {
  if ($1 <= $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op le(in STR, in STR, inconst INT) {
  if (string_compare(interpreter, $1, $2) <= 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op le(in PMC, in PMC, inconst INT) {
  if ($1->vtable->cmp(interpreter, $1, $2) <= 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op le(in PMC, in INT, inconst INT) {
  if ($1->vtable->get_integer(interpreter, $1) <= $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

########################################

=item B<gt>(in INT, in INT, inconst INT)

=item B<gt>(in NUM, in NUM, inconst INT)

=item B<gt>(in STR, in STR, inconst INT)

=item B<gt>(in PMC, in PMC, inconst INT)

Branch if $1 is greater than $2.

=cut

inline op gt(in INT, in INT, inconst INT) {
  if ($1 > $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

inline op gt(in NUM, in NUM, inconst INT) {
  if ($1 > $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op gt(in STR, in STR, inconst INT) {
  if (string_compare(interpreter, $1, $2) > 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op gt(in PMC, in PMC, inconst INT) {
  if ($1->vtable->cmp(interpreter, $1, $2) > 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

########################################

=item B<ge>(in INT, in INT, inconst INT)

=item B<ge>(in NUM, in NUM, inconst INT)

=item B<ge>(in STR, in STR, inconst INT)

=item B<ge>(in PMC, in PMC, inconst INT)

Branch if $1 is greater than or equal to $2.

=cut

inline op ge(in INT, in INT, inconst INT) {
  if ($1 >= $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

inline op ge(in NUM, in NUM, inconst INT) {
  if ($1 >= $2) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op ge(in STR, in STR, inconst INT) {
  if (string_compare(interpreter, $1, $2) >= 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

op ge(in PMC, in PMC, inconst INT) {
  if ($1->vtable->cmp(interpreter, $1, $2) >= 0) {
    goto OFFSET($3);
  }
  goto NEXT();
}

=back

=cut

###############################################################################

=head2 Flow control comparison operators

These operators branch based on the relationship between
their operands.

=over 4

=cut

########################################

=item B<cmp>(out INT, in INT, in INT)

=item B<cmp>(out INT, in NUM, in NUM)

=item B<cmp>(out INT, in STR, in STR)

=item B<cmp>(out INT, in PMC, in PMC)

Sets $1 to -1 if $2 < $3, +1 if $2 > $3, and 0 otherwise.

=cut

inline op cmp(out INT, in INT, in INT) {
  $1 = $2 < $3 ? -1 :
       $2 > $3 ? +1 :
       0;
  goto NEXT();
}

inline op cmp(out INT, in NUM, in NUM) {
  $1 = $2 < $3 ? -1 :
       $2 > $3 ? +1 :
       0;
  goto NEXT();
}

inline op cmp(out INT, in STR, in STR) {
  $1 = string_compare(interpreter, $2, $3);
  goto NEXT();
}

inline op cmp(out INT, in PMC, in PMC) {
  $1 = VTABLE_cmp(interpreter, $2, $3);
  goto NEXT();
}

=back

=cut

###############################################################################

=head2 Logical operations

These operations apply logical functions to their arguments.

=over 4

=cut

########################################

=item B<and>(out INT, in INT, in INT)

=item B<and>(in PMC, in PMC, in PMC)

Short-circuiting logical and.  Returns $2 if it's false, else returns $3.

=cut

inline op and(out INT, in INT, in INT) {
  $1 = $2 ? $3 : $2;
  goto NEXT();
}

inline op and(in PMC, in PMC, in PMC) {
  $2->vtable->logical_and(interpreter, $2, $3, $1);
  goto NEXT();
}

########################################

=item B<not>(out INT, in INT)

=item B<not>(in PMC, in PMC)

Set the boolean state of $1 to the opposite of the boolean state from $2.

=cut

inline op not(out INT, in INT) {
  $1 = ! $2;
  goto NEXT();
}

inline op not(in PMC, in PMC) {
  $2->vtable->logical_not(interpreter, $2, $1);
  goto NEXT();
}

########################################

=item B<or>(out INT, in INT, in INT)

=item B<or>(in PMC, in PMC, in PMC)

Short-circuiting logical or.  Returns $2 if it's true, else returns $3.

=cut

inline op or(out INT, in INT, in INT) {
  $1 = $2 ? $2 : $3;
  goto NEXT();
}

inline op or(in PMC, in PMC, in PMC) {
  $2->vtable->logical_or(interpreter, $2, $3, $1);
  goto NEXT();
}

########################################

=item B<xor>(out INT, in INT, in INT)

=item B<xor>(in PMC, in PMC, in PMC)

Logical xor.  Returns $2 if it's true and $3 isn't,
returns $3 if it's true and $2 isn't, else returns false.

=cut

inline op xor(out INT, in INT, in INT) {
  $1 = ($2 && ! $3) ? $2 : ($3 && ! $2) ? $3 : 0;
  goto NEXT();
}

inline op xor(in PMC, in PMC, in PMC) {
  $2->vtable->logical_xor(interpreter, $2, $3, $1);
  goto NEXT();
}

=back

=cut

###############################################################################

=head1 COPYRIGHT

Copyright (C) 2001-2003 The Perl Foundation.  All rights reserved.

=head1 LICENSE

This program is free software. It is subject to the same license
as the Parrot interpreter itself.

=cut
