<commit_before>use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl => unreachable!(),
                Shr => unreachable!(),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number of bits a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so 2^4 - 1 is the largest possible bitshift
            let mask_bits = match left {
                I8(_) => 3,
                I16(_) => 4,
                I32(_) => 5,
                I64(_) => 6,
                U8(_) => 3,
                U16(_) => 4,
                U32(_) => 5,
                U64(_) => 6,
                _ => unreachable!(),
            };
            let mask = (1 << mask_bits) - 1;
            let r = match right {
                I8(i) => i as u8 & mask,
                I16(i) => i as u8 & mask,
                I32(i) => i as u8 & mask,
                I64(i) => i as u8 & mask,
                U8(i) => i as u8 & mask,
                U16(i) => i as u8 & mask,
                U32(i) => i as u8 & mask,
                U64(i) => i as u8 & mask,
                _ => panic!("bad MIR: bitshift rhs is not integral"),
            };
            let r = r as u32;
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({<commit_msg>simplify even more<commit_after>use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl => unreachable!(),
                Shr => unreachable!(),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in that range
            let type_bits: u32 = match left {
                I8(_) | U8(_) => 8,
                I16(_) | U16(_) => 16,
                I32(_) | U32(_) => 32,
                I64(_) | U64(_) => 64,
                _ => unreachable!(),
            };
            assert!(type_bits.is_power_of_two());
            // turn into `u32` because `overflowing_sh{l,r}` only take `u32`
            let r = match right {
                I8(i) => i as u32,
                I16(i) => i as u32,
                I32(i) => i as u32,
                I64(i) => i as u32,
                U8(i) => i as u32,
                U16(i) => i as u32,
                U32(i) => i as u32,
                U64(i) => i as u32,
                _ => panic!("bad MIR: bitshift rhs is not integral"),
            };
            // apply mask
            let r = r & (type_bits - 1);
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({
{'fraction_non_alphanumeric': 0.16281806147962935, 'fraction_numerical': 0.027798205618473303, 'mean_word_length': 1.4381498745069918, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3253595', 'n_tokens_mistral': 2398, 'n_tokens_neox': 2223, 'n_words': 584}