Skip to main content

polydat_nodes/
bitwise.rs

1// Copyright 2024-2026 Jonathan Shook
2// SPDX-License-Identifier: Apache-2.0
3
4//! Bitwise and two-wire integer arithmetic nodes.
5//!
6//! These nodes operate on pairs of u64 wire inputs (no constants).
7//! They complement the existing const-param arithmetic nodes (`add`,
8//! `mul`, `div`, `mod`) which take one wire and one constant.
9//!
10//! All nodes support P2 (compiled_u64) and P3 (JIT) execution.
11
12#[polydat::polydat_node(category = Arithmetic, simd = "reg_add_i64", simd_total)]
13fn u64_add(a: u64, b: u64) -> u64 {
14    a.wrapping_add(b)
15}
16
17#[polydat::polydat_node(category = Arithmetic, simd = "reg_sub_i64", simd_total)]
18fn u64_sub(a: u64, b: u64) -> u64 {
19    a.wrapping_sub(b)
20}
21
22#[polydat::polydat_node(category = Arithmetic, simd = "reg_mul_i64", simd_total)]
23fn u64_mul(a: u64, b: u64) -> u64 {
24    a.wrapping_mul(b)
25}
26
27#[polydat::polydat_node(category = Arithmetic)]
28fn u64_div(a: u64, b: u64) -> u64 {
29    a.checked_div(b).unwrap_or(0)
30}
31
32#[polydat::polydat_node(category = Arithmetic)]
33fn u64_mod(a: u64, b: u64) -> u64 {
34    if b != 0 { a % b } else { 0 }
35}
36
37#[polydat::polydat_node(category = Arithmetic)]
38fn u64_and(a: u64, b: u64) -> u64 {
39    a & b
40}
41
42#[polydat::polydat_node(category = Arithmetic)]
43fn u64_or(a: u64, b: u64) -> u64 {
44    a | b
45}
46
47#[polydat::polydat_node(category = Arithmetic)]
48fn u64_xor(a: u64, b: u64) -> u64 {
49    a ^ b
50}
51
52#[polydat::polydat_node(category = Arithmetic)]
53fn u64_shl(a: u64, b: u64) -> u64 {
54    a.wrapping_shl(b as u32)
55}
56
57#[polydat::polydat_node(category = Arithmetic)]
58fn u64_shr(a: u64, b: u64) -> u64 {
59    a.wrapping_shr(b as u32)
60}
61
62#[polydat::polydat_node(category = Arithmetic)]
63fn u64_not(input: u64) -> u64 {
64    !input
65}
66
67#[polydat::polydat_node(category = Arithmetic)]
68fn checked_add(a: u64, b: u64) -> u64 {
69    a.checked_add(b).unwrap_or(0)
70}
71
72#[polydat::polydat_node(category = Arithmetic)]
73fn checked_sub(a: u64, b: u64) -> u64 {
74    a.saturating_sub(b)
75}
76
77#[polydat::polydat_node(category = Arithmetic)]
78fn checked_mul(a: u64, b: u64) -> u64 {
79    a.checked_mul(b).unwrap_or(0)
80}
81
82#[cfg(any())] // dead-code preserved verbatim for diff readability; never compiled
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use polydat::ast::{PolydatNode, Value};
87
88    #[test]
89    fn checked_add_normal() {
90        let node = CheckedAdd::new();
91        let mut out = [Value::None];
92        node.eval(&[Value::U64(100), Value::U64(42)], &mut out);
93        assert_eq!(out[0].as_u64(), 142);
94    }
95
96    #[test]
97    fn checked_add_overflow_returns_zero() {
98        let node = CheckedAdd::new();
99        let mut out = [Value::None];
100        node.eval(&[Value::U64(u64::MAX), Value::U64(1)], &mut out);
101        assert_eq!(out[0].as_u64(), 0);
102    }
103
104    #[test]
105    fn checked_sub_normal() {
106        let node = CheckedSub::new();
107        let mut out = [Value::None];
108        node.eval(&[Value::U64(42), Value::U64(10)], &mut out);
109        assert_eq!(out[0].as_u64(), 32);
110    }
111
112    #[test]
113    fn checked_sub_underflow_returns_zero() {
114        let node = CheckedSub::new();
115        let mut out = [Value::None];
116        node.eval(&[Value::U64(0), Value::U64(1)], &mut out);
117        assert_eq!(out[0].as_u64(), 0);
118    }
119
120    #[test]
121    fn checked_mul_normal() {
122        let node = CheckedMul::new();
123        let mut out = [Value::None];
124        node.eval(&[Value::U64(7), Value::U64(6)], &mut out);
125        assert_eq!(out[0].as_u64(), 42);
126    }
127
128    #[test]
129    fn checked_mul_overflow_returns_zero() {
130        let node = CheckedMul::new();
131        let mut out = [Value::None];
132        node.eval(&[Value::U64(u64::MAX), Value::U64(2)], &mut out);
133        assert_eq!(out[0].as_u64(), 0);
134    }
135
136    #[test]
137    fn u64_and_basic() {
138        let node = U64And::new();
139        let mut out = [Value::None];
140        node.eval(&[Value::U64(0xFF00), Value::U64(0x0FF0)], &mut out);
141        assert_eq!(out[0].as_u64(), 0x0F00);
142    }
143
144    #[test]
145    fn u64_or_basic() {
146        let node = U64Or::new();
147        let mut out = [Value::None];
148        node.eval(&[Value::U64(0xF0), Value::U64(0x0F)], &mut out);
149        assert_eq!(out[0].as_u64(), 0xFF);
150    }
151
152    #[test]
153    fn u64_xor_basic() {
154        let node = U64Xor::new();
155        let mut out = [Value::None];
156        node.eval(&[Value::U64(0xFF), Value::U64(0x0F)], &mut out);
157        assert_eq!(out[0].as_u64(), 0xF0);
158    }
159
160    #[test]
161    fn u64_shl_basic() {
162        let node = U64Shl::new();
163        let mut out = [Value::None];
164        node.eval(&[Value::U64(1), Value::U64(8)], &mut out);
165        assert_eq!(out[0].as_u64(), 256);
166    }
167
168    #[test]
169    fn u64_shr_basic() {
170        let node = U64Shr::new();
171        let mut out = [Value::None];
172        node.eval(&[Value::U64(256), Value::U64(4)], &mut out);
173        assert_eq!(out[0].as_u64(), 16);
174    }
175
176    #[test]
177    fn u64_not_basic() {
178        let node = U64Not::new();
179        let mut out = [Value::None];
180        node.eval(&[Value::U64(0)], &mut out);
181        assert_eq!(out[0].as_u64(), u64::MAX);
182    }
183
184    #[test]
185    fn u64_add2_wrapping() {
186        let node = U64Add::default();
187        let mut out = [Value::None];
188        node.eval(&[Value::U64(u64::MAX), Value::U64(1)], &mut out);
189        assert_eq!(out[0].as_u64(), 0);
190    }
191
192    #[test]
193    fn u64_div2_zero_divisor() {
194        let node = U64Div::default();
195        let mut out = [Value::None];
196        node.eval(&[Value::U64(42), Value::U64(0)], &mut out);
197        assert_eq!(out[0].as_u64(), 0);
198    }
199
200    #[test]
201    fn u64_sub2_wrapping() {
202        let node = U64Sub::default();
203        let mut out = [Value::None];
204        node.eval(&[Value::U64(0), Value::U64(1)], &mut out);
205        assert_eq!(out[0].as_u64(), u64::MAX);
206    }
207
208    #[test]
209    fn u64_mul2_basic() {
210        let node = U64Mul::default();
211        let mut out = [Value::None];
212        node.eval(&[Value::U64(7), Value::U64(6)], &mut out);
213        assert_eq!(out[0].as_u64(), 42);
214    }
215
216    #[test]
217    fn u64_mod2_basic() {
218        let node = U64Mod::default();
219        let mut out = [Value::None];
220        node.eval(&[Value::U64(42), Value::U64(10)], &mut out);
221        assert_eq!(out[0].as_u64(), 2);
222    }
223
224    #[test]
225    fn u64_mod2_zero_divisor() {
226        let node = U64Mod::default();
227        let mut out = [Value::None];
228        node.eval(&[Value::U64(42), Value::U64(0)], &mut out);
229        assert_eq!(out[0].as_u64(), 0);
230    }
231}