use crate::stack::{Stack, pop, pop_two, push};
use crate::value::Value;
const I63_MIN: i64 = -(1i64 << 62);
const I63_MAX: i64 = (1i64 << 62) - 1;
const I63_MASK: u64 = (1u64 << 63) - 1;
#[inline]
fn fits_in_i63(v: i64) -> bool {
(I63_MIN..=I63_MAX).contains(&v)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_band(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "band") };
match (a, b) {
(Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val & b_val)) },
_ => panic!("band: expected two integers on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_bor(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "bor") };
match (a, b) {
(Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val | b_val)) },
_ => panic!("bor: expected two integers on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_bxor(stack: Stack) -> Stack {
let (rest, a, b) = unsafe { pop_two(stack, "bxor") };
match (a, b) {
(Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val ^ b_val)) },
_ => panic!("bxor: expected two integers on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_bnot(stack: Stack) -> Stack {
assert!(!stack.is_null(), "bnot: stack is empty");
let (rest, a) = unsafe { pop(stack) };
match a {
Value::Int(a_val) => unsafe { push(rest, Value::Int(!a_val)) },
_ => panic!("bnot: expected integer on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_shl(stack: Stack) -> Stack {
let (rest, value, count) = unsafe { pop_two(stack, "shl") };
match (value, count) {
(Value::Int(v), Value::Int(c)) => {
let result = if !(0..64).contains(&c) {
0
} else {
let raw = v.checked_shl(c as u32).unwrap_or(0);
if fits_in_i63(raw) { raw } else { 0 }
};
unsafe { push(rest, Value::Int(result)) }
}
_ => panic!("shl: expected two integers on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_shr(stack: Stack) -> Stack {
let (rest, value, count) = unsafe { pop_two(stack, "shr") };
match (value, count) {
(Value::Int(v), Value::Int(c)) => {
let result = if !(0..64).contains(&c) {
0
} else {
let raw = (v as u64).checked_shr(c as u32).unwrap_or(0) as i64;
if fits_in_i63(raw) { raw } else { 0 }
};
unsafe { push(rest, Value::Int(result)) }
}
_ => panic!("shr: expected two integers on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_popcount(stack: Stack) -> Stack {
assert!(!stack.is_null(), "popcount: stack is empty");
let (rest, a) = unsafe { pop(stack) };
match a {
Value::Int(v) => {
let count = ((v as u64) & I63_MASK).count_ones() as i64;
unsafe { push(rest, Value::Int(count)) }
}
_ => panic!("popcount: expected integer on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_clz(stack: Stack) -> Stack {
assert!(!stack.is_null(), "clz: stack is empty");
let (rest, a) = unsafe { pop(stack) };
match a {
Value::Int(v) => {
let lz = (v.leading_zeros() as i64).saturating_sub(1);
unsafe { push(rest, Value::Int(lz)) }
}
_ => panic!("clz: expected integer on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_ctz(stack: Stack) -> Stack {
assert!(!stack.is_null(), "ctz: stack is empty");
let (rest, a) = unsafe { pop(stack) };
match a {
Value::Int(v) => {
let tz = if v == 0 {
63
} else {
v.trailing_zeros() as i64
};
unsafe { push(rest, Value::Int(tz)) }
}
_ => panic!("ctz: expected integer on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_int_bits(stack: Stack) -> Stack {
unsafe { push(stack, Value::Int(63)) }
}