/*
 * $Id: bit.ops 47428 2010-06-06 08:32:34Z cotto $
** bit.ops
*/

BEGIN_OPS_PREAMBLE
 /* Signed shift operator that is compatible with PMC shifts.  This is
  * guaranteed to produce the same result as bitwise_left_shift_internal modulo
  * word size, ignoring the fact that Parrot integers are always signed.  This
  * usually gives the same answer regardless whether you shift PMC operands and
  * then assign to an I-reg, or move the operands to I-regs and do the shift
  * there -- except when the true result is between 2^{w-1} and 2^w (where w is
  * the word size), in which case the high order bit is taken as the sign,
  * giving a truncated result that is 2^w lower.
  */
#define bit_shift_left(number, bits) \
    ((bits) >= 8*INTVAL_SIZE     ? 0                    \
     : (bits) >= 0               ? (number) << (bits)   \
     : (bits) > -8*INTVAL_SIZE   ? (number) >> -(bits)   \
     : 0)

END_OPS_PREAMBLE

=head1 NAME

bit.ops - Bitwise Opcodes

=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.

When making changes to any ops file, run C<make bootstrap-ops> to regenerate
all generated ops files.

=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;
}

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

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

=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;
}

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

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

=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 = bit_shift_left($1, $2);
}

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

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

=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 {
    const INTVAL signed_shift = -$2;
    $1 = bit_shift_left($1, signed_shift);
}

inline op shr(out INT, in INT, in INT) :base_core {
    const INTVAL signed_shift = -$3;
    $1 = bit_shift_left($2, signed_shift);
}

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

=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 {
    const UINTVAL a = (UINTVAL)$1;
    const UINTVAL b = a >> $2;
    $1 = (INTVAL)b;
}

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

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

=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;
}

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

=back

=cut

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

=head1 COPYRIGHT

Copyright (C) 2001-2010, Parrot 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:
 */
