synthphonia/expr/ops/bv/
mod.rs

1use crate::{
2    expr::ops, forward::enumeration, galloc::AllocForExactSizeIter, impl_basic, new_op1,
3    value::Value,
4};
5
6fn mask(i: usize) -> u64 { 
7    (1u64 << i) - 1
8}
9fn to_signed(i: usize, a: u64) -> i64 {
10    if a & (1u64 << (i - 1)) != 0 {
11        (a | !mask(i)) as i64
12    } else {
13        a as i64
14    }
15}
16
17impl_basic!(BvNot, "bvnot");
18impl enumeration::Enumerator1 for BvNot {}
19impl ops::Op1 for BvNot {
20    fn cost(&self) -> usize { self.0 }
21
22    fn try_eval(&self, a1: Value) -> (bool, Value) {
23        if let Value::BitVector(i, a1) = a1 {
24            (true, Value::BitVector(i, a1.iter().map(|x| !x & mask(i)).galloc_scollect()))
25        } else {
26            (false, Value::Null)
27        }
28    }
29}
30
31impl_basic!(BvNeg, "bvneg");
32impl enumeration::Enumerator1 for BvNeg {}
33impl ops::Op1 for BvNeg {
34    fn cost(&self) -> usize { self.0 }
35
36    fn try_eval(&self, a1: Value) -> (bool, Value) {
37        if let Value::BitVector(i, a1) = a1 {
38            (true, Value::BitVector(i, a1.iter().map(|x| (0u64 - x) & mask(i)).galloc_scollect()))
39        } else {
40            (false, Value::Null)
41        }
42    }
43}
44
45macro_rules! impl_bvop2 {
46    ($op:ident, $name:literal, $f:expr) => {
47        impl_basic!($op, $name);
48        impl enumeration::Enumerator2 for $op {}
49        impl ops::Op2 for $op {
50            fn cost(&self) -> usize { self.0 }
51
52            fn try_eval(&self, a1: Value, a2: Value) -> (bool, Value) {
53                if let (Value::BitVector(i1, a1), Value::BitVector(i2, a2)) = (a1, a2) {
54                    $f(i1, a1, i2, a2)
55                } else {
56                    (false, Value::Null)
57                }
58            }
59        }
60    };
61}
62
63impl_bvop2!(BvAdd, "bvadd", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
64    let i = std::cmp::max(i1, i2);
65    let result = a1.iter().zip(a2.iter()).map(|(x, y)| (x + y) & mask(i)).galloc_scollect();
66    (true, Value::BitVector(i, result))
67});
68impl_bvop2!(BvSub, "bvsub", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
69    let i = std::cmp::max(i1, i2);
70    let result = a1.iter().zip(a2.iter()).map(|(x, y)| (x - y) & mask(i)).galloc_scollect();
71    (true, Value::BitVector(i, result))
72});
73impl_bvop2!(BvMul, "bvmul", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
74    let i = std::cmp::max(i1, i2);
75    let result = a1.iter().zip(a2.iter()).map(|(x, y)| (x * y) & mask(i)).galloc_scollect();
76    (true, Value::BitVector(i, result))
77});
78
79impl_bvop2!(BvAnd, "bvand", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
80    let i = std::cmp::max(i1, i2);
81    let result = a1.iter().zip(a2.iter()).map(|(x, y)| x & y).galloc_scollect();
82    (true, Value::BitVector(i, result))
83});
84impl_bvop2!(BvOr, "bvor", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
85    let i = std::cmp::max(i1, i2);
86    let result = a1.iter().zip(a2.iter()).map(|(x, y)| x | y).galloc_scollect();
87    (true, Value::BitVector(i, result))
88});
89impl_bvop2!(BvXor, "bvxor", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
90    let i = std::cmp::max(i1, i2);
91    let result = a1.iter().zip(a2.iter()).map(|(x, y)| x ^ y).galloc_scollect();
92    (true, Value::BitVector(i, result))
93});
94
95impl_bvop2!(BvShl, "bvshl", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
96    let i = std::cmp::max(i1, i2);
97    let result = a1.iter().zip(a2.iter()).map(|(x, y)| if *y >= 64 {0} else { (x << y) & mask(i) }).galloc_scollect();
98    (true, Value::BitVector(i, result))
99});
100impl_bvop2!(BvLShr, "bvlshr", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
101    let i = std::cmp::max(i1, i2);
102    let result = a1.iter().zip(a2.iter()).map(|(x, y)| if *y >= 64 {0} else { x >> y }).galloc_scollect();
103    (true, Value::BitVector(i, result))
104});
105impl_bvop2!(BvAShr, "bvashr", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
106    let i = std::cmp::max(i1, i2);
107    let result = a1.iter().zip(a2.iter()).map(|(x, y)| if *y >= 64 {0} else { (to_signed(i, *x) >> y) as u64 & mask(i) }).galloc_scollect();
108    (true, Value::BitVector(i, result))
109});
110
111impl_bvop2!(BvUDiv, "bvudiv", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
112    if a2.iter().any(|&x| x == 0) {
113        return (false, Value::Null);
114    }
115    let i = std::cmp::max(i1, i2);
116    let result = a1.iter().zip(a2.iter()).map(|(x, y)| x / y).galloc_scollect();
117    (true, Value::BitVector(i, result))
118});
119
120impl_bvop2!(BvSDiv, "bvsdiv", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
121    if a2.iter().any(|&x| x == 0) {
122        return (false, Value::Null);
123    }
124    let i = std::cmp::max(i1, i2);
125    let result = a1.iter().zip(a2.iter()).map(|(x, y)| to_signed(i, *x).overflowing_div(to_signed(i, *y)).0 as u64 & mask(i)).galloc_scollect();
126    (true, Value::BitVector(i, result))
127});
128
129impl_bvop2!(BvURem, "bvurem", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
130    if a2.iter().any(|&x| x == 0) {
131        return (false, Value::Null);
132    }
133    let i = std::cmp::max(i1, i2);
134    let result = a1.iter().zip(a2.iter()).map(|(x, y)| x % y).galloc_scollect();
135    (true, Value::BitVector(i, result))
136});
137
138impl_bvop2!(BvSRem, "bvsrem", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
139    if a2.iter().any(|&x| x == 0) {
140        return (false, Value::Null);
141    }
142    let i = std::cmp::max(i1, i2);
143    let result = a1.iter().zip(a2.iter()).map(|(x, y)| to_signed(i, *x).overflowing_rem(to_signed(i, *y)).0 as u64 & mask(i)).galloc_scollect();
144    (true, Value::BitVector(i, result))
145});
146
147
148impl_bvop2!(BvSlt, "bvslt", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
149    let i = std::cmp::max(i1, i2);
150    let result = a1.iter().zip(a2.iter()).map(|(x, y)| to_signed(i, *x) < to_signed(i, *y)).galloc_scollect();
151    (true, Value::Bool(result))
152});
153impl_bvop2!(BvUlt, "bvult", |i1, a1: &'static [u64], i2, a2: &'static [u64]| {
154    let i = std::cmp::max(i1, i2);
155    let result = a1.iter().zip(a2.iter()).map(|(x, y)| x < y).galloc_scollect();
156    (true, Value::Bool(result))
157});
158