/*
** bit.ops
*/

VERSION = PARROT_VERSION;

=head1 NAME

bit.ops - Bitwise Operations

=head1 DESCRIPTION

Operations that deal with bits directly, either individually
or in groups.

The variant with an appended B<s> like B<bands> work on strings.

The variants with a prepended B<n_> like <n_bnot> generate a new target PMC.
If possible, they use the appropriate language type, specified with C<.HLL>.

=over 4

=cut

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

=item B<band>(inout INT, in INT)

Set the bits of $1 according to the B<and> of the corresponding bits
from $1 and $2.

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

Set the bits of $1 according to the B<and> of the corresponding bits
from $2 and $3.

=cut

inline op band(inout INT, in INT) :base_core {
  $1 &= $2;
  goto NEXT();
}

inline op band(out INT, in INT, in INT) :base_core {
  $1 = $2 & $3;
  goto NEXT();
}

=item B<bands>(inout STR, in STR)

Set the bits of $1 according to the B<and> of the corresponding bits
from $1 and $2.

=item B<bands>(out STR, in STR, in STR)

Set the bits of $1 according to the B<and> of the corresponding bits
from $2 and $3.

=cut

inline op bands(inout STR, in STR) :base_core {
  string_bitwise_and(interp, $1, $2, &$1);
  goto NEXT();
}

inline op bands(out STR, in STR, in STR) :base_core {
  $1 = string_bitwise_and(interp, $2, $3, NULL);
  goto NEXT();
}

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

=item B<bnot>(inout INT)

=item B<bnot>(invar PMC)

Sets $1 to C<bitwise not> $1 inplace.

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

=item B<bnot>(out PMC, invar PMC)

=item B<n_bnot>(out PMC, invar PMC)

Set the bits of $1 to the B<not> of the corresponding bits from $2.

=cut

inline op bnot(inout INT) :base_core {
  $1 = ~ $1;
  goto NEXT();
}

inline op bnot(out INT, in INT) :base_core {
  $1 = ~ $2;
  goto NEXT();
}

inline op bnot(invar PMC) :base_core {
  $1->vtable->i_bitwise_not(interp, $1);
  goto NEXT();
}

inline op bnot(out PMC, invar PMC) :base_core {
  $1 = $2->vtable->bitwise_not(interp, $2, $1);
  goto NEXT();
}

inline op n_bnot(out PMC, invar PMC) :base_core {
  $1 = $2->vtable->bitwise_not(interp, $2, NULL);
  goto NEXT();
}

=item B<bnots>(inout STR)

=item B<bnots>(invar PMC)

=item B<bnots>(out STR, in STR)

=item B<bnots>(out PMC, invar PMC)

=item B<n_bnots>(out PMC, invar PMC)

Set the bits of $1 to the B<not> of the corresponding bits from $2.

=cut

inline op bnots(inout STR) :base_core {
  string_bitwise_not(interp, $1, &$1);
  goto NEXT();
}

inline op bnots(out STR, in STR) :base_core {
  string_bitwise_not(interp, $2, &$1);
  goto NEXT();
}

inline op bnots(invar PMC) :base_core {
  $1->vtable->i_bitwise_nots(interp, $1);
  goto NEXT();
}

inline op bnots(out PMC, invar PMC) :base_core {
  $1 = $2->vtable->bitwise_nots(interp, $2, $1);
  goto NEXT();
}

inline op n_bnots(out PMC, invar PMC) :base_core {
  $1 = $2->vtable->bitwise_nots(interp, $2, NULL);
  goto NEXT();
}

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

=item B<bor>(inout INT, in INT)

Set the bits of $1 according to the B<or> of the corresponding bits
from $1 and $2.

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

Set the bits of $1 according to the B<or> of the corresponding bits
from $2 and $3.

=cut

inline op bor(inout INT, in INT) :base_core {
  $1 |= $2;
  goto NEXT();
}

inline op bor(out INT, in INT, in INT) :base_core {
  $1 = $2 | $3;
  goto NEXT();
}

=item B<bors>(inout STR, in STR)

Set the bits of $1 according to the B<or> of the corresponding bits
from $1 and $2.

=item B<bors>(out STR, in STR, in STR)

Set the bits of $1 according to the B<or> of the corresponding bits
from $2 and $3.

=cut

inline op bors(inout STR, in STR) :base_core {
  string_bitwise_or(interp, $1, $2, &$1);
  goto NEXT();
}

inline op bors(out STR, in STR, in STR) :base_core {
  $1 = string_bitwise_or(interp, $2, $3, NULL);
  goto NEXT();
}

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

=item B<shl>(inout INT, in INT)

Shift left $1 by $2 bits.

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

Set $1 to the value of $2 shifted left by $3 bits.

=cut

inline op shl(inout INT, in INT) :base_core {
  $1 <<= $2;
  goto NEXT();
}

inline op shl(out INT, in INT, in INT) :base_core {
  $1 = $2 << $3;
  goto NEXT();
}

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

=item B<shr>(inout INT, in INT)

Shift right $1 by $2 bits.

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

Set $1 to the value of $2 shifted right by $3 bits.

=cut

inline op shr(inout INT, in INT) :base_core {
  $1 >>= $2;
  goto NEXT();
}

inline op shr(out INT, in INT, in INT) :base_core {
  $1 = $2 >> $3;
  goto NEXT();
}

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

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

Shift $1 logically shifted right by $2 bits.

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

Set $1 to the value of $2 logically shifted right by $3 bits.

=cut

inline op lsr(out INT, in INT) :base_core {
  /*
   * lvalue casts are evil, but this one isn't evil enough to kill.
   * it's just casting a signed integral to the equivalent unsigned.
   */
  LVALUE_CAST(UINTVAL, $1) >>= $2;
  goto NEXT();
}

inline op lsr(out INT, in INT, in INT) :base_core {
  $1 = (INTVAL)((UINTVAL)$2 >> $3);
  goto NEXT();
}

=item B<rot>(out INT, in INT, in INT, inconst INT)

Rotate $2 left or right by $3 and place result in $1.
$4 is the amount of bits to rotate, 32 bit on a 32-bit CPU and 32 or 64
on a 64-bit CPU. If the rotate count is negative a rotate right by ($3+$4)
is performed.

=cut

inline op rot(out INT, in INT, in INT, inconst INT) {
  const INTVAL r = $2;
  INTVAL s = $3;
  const INTVAL w = $4;
  INTVAL d, t;
  if (s < 0)
    s += w;
  d = r << s;
  t = w - s;
  t = (INTVAL)((UINTVAL)r >> t);
  d |= t;
  $1 = d;
  goto NEXT();
}


}

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

=item B<bxor>(inout INT, in INT)

Set the bits of $1 according to the B<xor> of the corresponding bits
from $1 and $2.

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

Set the bits of $1 according to the B<xor> of the corresponding bits
from $2 and $3.

=cut

inline op bxor(inout INT, in INT) :base_core {
  $1 ^= $2;
  goto NEXT();
}

inline op bxor(out INT, in INT, in INT) :base_core {
  $1 = $2 ^ $3;
  goto NEXT();
}

=item B<bxors>(inout STR, in STR)

Set the bits of $1 according to the B<xor> of the corresponding bits
from $1 and $2.

=item B<bxors>(out STR, in STR, in STR)

Set the bits of $1 according to the B<xor> of the corresponding bits
from $2 and $3.

=cut

inline op bxors(inout STR, in STR) :base_core {
  string_bitwise_xor(interp, $1, $2, &$1);
  goto NEXT();
}

inline op bxors(out STR, in STR, in STR) :base_core {
  $1 = string_bitwise_xor(interp, $2, $3, NULL);
  goto NEXT();
}

=back

=cut

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

=head1 COPYRIGHT

Copyright (C) 2001-2006, The Perl Foundation.

=head1 LICENSE

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

=cut

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
