Skip to main content

seq_runtime/arithmetic/
bitwise.rs

1//! Bitwise operations: `band`, `bor`, `bxor`, `bnot`, `shl`, `shr`,
2//! plus bit-counting intrinsics (`popcount`, `clz`, `ctz`) and
3//! `int_bits` (raw bit pattern as integer).
4
5use crate::stack::{Stack, pop, pop_two, push};
6use crate::value::Value;
7
8// ============================================================================
9// Bitwise Operations
10// ============================================================================
11
12/// Bitwise AND
13///
14/// Stack effect: ( a b -- a&b )
15///
16/// # Safety
17/// Stack must have two Int values on top
18#[unsafe(no_mangle)]
19pub unsafe extern "C" fn patch_seq_band(stack: Stack) -> Stack {
20    let (rest, a, b) = unsafe { pop_two(stack, "band") };
21    match (a, b) {
22        (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val & b_val)) },
23        _ => panic!("band: expected two integers on stack"),
24    }
25}
26
27/// Bitwise OR
28///
29/// Stack effect: ( a b -- a|b )
30///
31/// # Safety
32/// Stack must have two Int values on top
33#[unsafe(no_mangle)]
34pub unsafe extern "C" fn patch_seq_bor(stack: Stack) -> Stack {
35    let (rest, a, b) = unsafe { pop_two(stack, "bor") };
36    match (a, b) {
37        (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val | b_val)) },
38        _ => panic!("bor: expected two integers on stack"),
39    }
40}
41
42/// Bitwise XOR
43///
44/// Stack effect: ( a b -- a^b )
45///
46/// # Safety
47/// Stack must have two Int values on top
48#[unsafe(no_mangle)]
49pub unsafe extern "C" fn patch_seq_bxor(stack: Stack) -> Stack {
50    let (rest, a, b) = unsafe { pop_two(stack, "bxor") };
51    match (a, b) {
52        (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val ^ b_val)) },
53        _ => panic!("bxor: expected two integers on stack"),
54    }
55}
56
57/// Bitwise NOT (one's complement)
58///
59/// Stack effect: ( a -- !a )
60///
61/// # Safety
62/// Stack must have one Int value on top
63#[unsafe(no_mangle)]
64pub unsafe extern "C" fn patch_seq_bnot(stack: Stack) -> Stack {
65    assert!(!stack.is_null(), "bnot: stack is empty");
66    let (rest, a) = unsafe { pop(stack) };
67    match a {
68        Value::Int(a_val) => unsafe { push(rest, Value::Int(!a_val)) },
69        _ => panic!("bnot: expected integer on stack"),
70    }
71}
72
73/// Shift left
74///
75/// Stack effect: ( value count -- result )
76/// Shifts value left by count bits. Negative count or count >= 64 returns 0.
77///
78/// # Safety
79/// Stack must have two Int values on top
80#[unsafe(no_mangle)]
81pub unsafe extern "C" fn patch_seq_shl(stack: Stack) -> Stack {
82    let (rest, value, count) = unsafe { pop_two(stack, "shl") };
83    match (value, count) {
84        (Value::Int(v), Value::Int(c)) => {
85            // Use checked_shl to avoid undefined behavior for out-of-range shifts
86            // Negative counts become large u32 values, which correctly return None
87            let result = if c < 0 {
88                0
89            } else {
90                v.checked_shl(c as u32).unwrap_or(0)
91            };
92            unsafe { push(rest, Value::Int(result)) }
93        }
94        _ => panic!("shl: expected two integers on stack"),
95    }
96}
97
98/// Logical shift right (zero-fill)
99///
100/// Stack effect: ( value count -- result )
101/// Shifts value right by count bits, filling with zeros.
102/// Negative count or count >= 64 returns 0.
103///
104/// # Safety
105/// Stack must have two Int values on top
106#[unsafe(no_mangle)]
107pub unsafe extern "C" fn patch_seq_shr(stack: Stack) -> Stack {
108    let (rest, value, count) = unsafe { pop_two(stack, "shr") };
109    match (value, count) {
110        (Value::Int(v), Value::Int(c)) => {
111            // Use checked_shr to avoid undefined behavior for out-of-range shifts
112            // Cast to u64 for logical (zero-fill) shift behavior
113            let result = if c < 0 {
114                0
115            } else {
116                (v as u64).checked_shr(c as u32).unwrap_or(0) as i64
117            };
118            unsafe { push(rest, Value::Int(result)) }
119        }
120        _ => panic!("shr: expected two integers on stack"),
121    }
122}
123
124/// Population count (count number of 1 bits)
125///
126/// Stack effect: ( n -- count )
127///
128/// # Safety
129/// Stack must have one Int value on top
130#[unsafe(no_mangle)]
131pub unsafe extern "C" fn patch_seq_popcount(stack: Stack) -> Stack {
132    assert!(!stack.is_null(), "popcount: stack is empty");
133    let (rest, a) = unsafe { pop(stack) };
134    match a {
135        Value::Int(v) => unsafe { push(rest, Value::Int(v.count_ones() as i64)) },
136        _ => panic!("popcount: expected integer on stack"),
137    }
138}
139
140/// Count leading zeros
141///
142/// Stack effect: ( n -- count )
143///
144/// # Safety
145/// Stack must have one Int value on top
146#[unsafe(no_mangle)]
147pub unsafe extern "C" fn patch_seq_clz(stack: Stack) -> Stack {
148    assert!(!stack.is_null(), "clz: stack is empty");
149    let (rest, a) = unsafe { pop(stack) };
150    match a {
151        Value::Int(v) => unsafe { push(rest, Value::Int(v.leading_zeros() as i64)) },
152        _ => panic!("clz: expected integer on stack"),
153    }
154}
155
156/// Count trailing zeros
157///
158/// Stack effect: ( n -- count )
159///
160/// # Safety
161/// Stack must have one Int value on top
162#[unsafe(no_mangle)]
163pub unsafe extern "C" fn patch_seq_ctz(stack: Stack) -> Stack {
164    assert!(!stack.is_null(), "ctz: stack is empty");
165    let (rest, a) = unsafe { pop(stack) };
166    match a {
167        Value::Int(v) => unsafe { push(rest, Value::Int(v.trailing_zeros() as i64)) },
168        _ => panic!("ctz: expected integer on stack"),
169    }
170}
171
172/// Push the bit width of Int (64)
173///
174/// Stack effect: ( -- 64 )
175///
176/// # Safety
177/// Always safe to call
178#[unsafe(no_mangle)]
179pub unsafe extern "C" fn patch_seq_int_bits(stack: Stack) -> Stack {
180    unsafe { push(stack, Value::Int(64)) }
181}