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