1use std::sync::LazyLock;
20
21use crate::symcc::type_abbrevs::{Int, Nat, Width};
22use miette::Diagnostic;
23use num_bigint::{BigInt, BigUint, ToBigInt};
24use num_traits::cast::ToPrimitive;
25use thiserror::Error;
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
32pub struct BitVec {
33 width: Width,
34 v: BigUint,
35}
36
37static TWO: LazyLock<BigUint> = LazyLock::new(|| BigUint::from(2u128));
38
39#[derive(Debug, Diagnostic, Error)]
41pub enum BitVecError {
42 #[error("extract out of bounds")]
44 ExtractOutOfBounds,
45 #[error("mismatched bit-vector widths in {0}")]
47 MismatchedWidths(String),
48 #[error("shift amount too large to fit in u32")]
50 ShiftAmountTooLarge,
51}
52
53type Result<T> = std::result::Result<T, BitVecError>;
54
55impl BitVec {
56 pub fn of_nat(width: Width, v: Nat) -> Self {
60 BitVec::new(width, v)
61 }
62
63 pub fn of_int(width: Width, v: Int) -> Self {
67 if v >= BigInt::ZERO {
68 #[expect(
69 clippy::unwrap_used,
70 reason = "already checked that `v` is nonnegative, so `to_biguint()` will return `Some`."
71 )]
72 BitVec::new(width, v.to_biguint().unwrap())
73 } else {
74 #[expect(
76 clippy::unwrap_used,
77 reason = "Safe because -v is guaranteed to be positive now."
78 )]
79 let pos = BitVec::new(width, (-v).to_biguint().unwrap());
80 #[expect(
81 clippy::expect_used,
82 reason = "Both arguments have width equal to `width`"
83 )]
84 BitVec::add(&pos.not(), &BitVec::of_nat(width, BigUint::from(1u128)))
85 .expect("both arguments have width equal to `width`")
86 }
87 }
88
89 pub fn of_u128(width: Width, val: u128) -> Self {
93 BitVec::of_nat(width, BigUint::from(val))
94 }
95
96 pub fn of_i128(width: Width, val: i128) -> Self {
100 BitVec::of_int(width, BigInt::from(val))
101 }
102
103 pub fn to_nat(&self) -> Nat {
105 self.v.clone()
106 }
107
108 pub fn as_nat(&self) -> &Nat {
110 &self.v
111 }
112
113 pub fn to_int(&self) -> Int {
115 let sign_bit = self.msb();
116 if self.width.get() < 2 {
117 if sign_bit {
118 BigInt::from(-1)
119 } else {
120 BigInt::ZERO
121 }
122 } else {
123 #[expect(clippy::unwrap_used, reason = "Already checked that width is not < 2")]
126 let val = self.extract_bits(0, self.width.get() - 2).unwrap();
127 #[expect(
128 clippy::unwrap_used,
129 reason = "The implementation of BigUint::to_bigint always returns Some"
130 )]
131 let val_bigint = BigUint::to_bigint(&val.v).unwrap();
132 if !sign_bit {
133 val_bigint
134 } else {
135 #[expect(
136 clippy::unwrap_used,
137 reason = "The implementation of BigUint::to_bigint always returns Some"
138 )]
139 let res =
140 -1 * BigUint::to_bigint(&TWO.pow(self.width.get() - 1)).unwrap() + val_bigint;
141 res
142 }
143 }
144 }
145
146 pub fn extract_bits(&self, low: u32, high: u32) -> Result<Self> {
151 if low <= high && high < self.width.get() {
152 let rem = &self.v % TWO.pow(high + 1);
153 let quotient = rem / TWO.pow(low);
154 #[expect(
155 clippy::expect_used,
156 reason = "Because we add 1, the value cannot be 0"
157 )]
158 Ok(BitVec::of_nat(
159 Width::new(high - low + 1).expect("because we add 1, the value cannot be 0"),
160 quotient,
161 ))
162 } else {
163 Err(BitVecError::ExtractOutOfBounds)
164 }
165 }
166
167 fn new(width: Width, val: Nat) -> Self {
171 let v = val % TWO.pow(width.get());
173 BitVec { width, v }
174 }
175
176 fn all_ones(width: Width) -> Self {
178 let all_ones = TWO.pow(width.get() + 1) - 1u32;
179 BitVec::of_nat(width, all_ones)
180 }
181
182 fn msb(&self) -> bool {
184 #[expect(
185 clippy::unwrap_used,
186 reason = "these arguments to extract_bits must always satisfy low <= high < self.width. note that self.width is a NonZeroU32 and thus cannot be 0"
187 )]
188 let bit = self
189 .extract_bits(self.width.get() - 1, self.width.get() - 1)
190 .unwrap()
191 .v;
192 bit != BigUint::ZERO
193 }
194
195 fn is_zero(&self) -> bool {
197 self.v == BigUint::ZERO
198 }
199
200 pub const fn width(&self) -> Width {
206 self.width
207 }
208
209 pub fn signed_min(n: Width) -> Int {
213 #[expect(
215 clippy::unwrap_used,
216 reason = "The implementation of BigUint::to_bigint always returns Some"
217 )]
218 let two_to_n_minus_1 = BigUint::to_bigint(&TWO.pow(n.get() - 1)).unwrap();
219 -two_to_n_minus_1
220 }
221
222 pub fn signed_max(n: Width) -> Int {
224 #[expect(
226 clippy::unwrap_used,
227 reason = "The implementation of BigUint::to_bigint always returns Some"
228 )]
229 let two_to_n_minus_1 = BigUint::to_bigint(&TWO.pow(n.get() - 1)).unwrap();
230 two_to_n_minus_1 - 1
231 }
232
233 pub fn overflows(n: Width, i: &Int) -> bool {
235 i < &BitVec::signed_min(n) || i > &BitVec::signed_max(n)
236 }
237
238 pub fn not(&self) -> Self {
244 BitVec::of_nat(self.width, &self.v ^ BitVec::all_ones(self.width).v)
245 }
246
247 pub fn neg(&self) -> Self {
249 let one = BitVec::of_u128(self.width, 1);
250 #[expect(
251 clippy::unwrap_used,
252 reason = "`self.not()` and `one` have width equal to `self.width`"
253 )]
254 BitVec::add(&self.not(), &one).unwrap()
255 }
256
257 pub fn int_min(width: Width) -> Self {
261 BitVec::of_nat(width, TWO.pow(width.get() - 1))
262 }
263
264 pub fn slt(lhs: &Self, rhs: &Self) -> Result<bool> {
266 if lhs.width != rhs.width {
267 Err(BitVecError::MismatchedWidths("slt".into()))
268 } else {
269 Ok(lhs.to_int() < rhs.to_int())
270 }
271 }
272
273 pub fn sle(lhs: &Self, rhs: &Self) -> Result<bool> {
275 if lhs.width != rhs.width {
276 Err(BitVecError::MismatchedWidths("sle".into()))
277 } else {
278 Ok(lhs.to_int() <= rhs.to_int())
279 }
280 }
281
282 pub fn ule(lhs: &Self, rhs: &Self) -> Result<bool> {
284 if lhs.width != rhs.width {
285 Err(BitVecError::MismatchedWidths("ule".into()))
286 } else {
287 Ok(lhs.v <= rhs.v)
288 }
289 }
290
291 pub fn ult(lhs: &Self, rhs: &Self) -> Result<bool> {
293 if lhs.width != rhs.width {
294 Err(BitVecError::MismatchedWidths("ult".into()))
295 } else {
296 Ok(lhs.v < rhs.v)
297 }
298 }
299
300 pub fn add(lhs: &Self, rhs: &Self) -> Result<Self> {
305 if lhs.width != rhs.width {
306 Err(BitVecError::MismatchedWidths("add".into()))
307 } else {
308 Ok(BitVec::of_nat(lhs.width, &lhs.v + &rhs.v))
309 }
310 }
311
312 pub fn sub(lhs: &Self, rhs: &Self) -> Result<Self> {
317 if lhs.width != rhs.width {
318 Err(BitVecError::MismatchedWidths("sub".into()))
319 } else {
320 BitVec::add(lhs, &rhs.neg())
321 }
322 }
323
324 pub fn mul(lhs: &Self, rhs: &Self) -> Result<Self> {
329 if lhs.width != rhs.width {
330 Err(BitVecError::MismatchedWidths("mul".into()))
331 } else {
332 Ok(BitVec::of_nat(lhs.width, &lhs.v * &rhs.v))
333 }
334 }
335
336 pub fn udiv(lhs: &Self, rhs: &Self) -> Result<Self> {
343 if lhs.width != rhs.width {
344 return Err(BitVecError::MismatchedWidths("udiv".into()));
345 };
346 if rhs.v == BigUint::ZERO {
347 Ok(BitVec::all_ones(lhs.width))
348 } else {
349 Ok(BitVec::of_nat(lhs.width, &lhs.v / &rhs.v))
350 }
351 }
352
353 pub fn urem(lhs: &Self, rhs: &Self) -> Result<Self> {
360 if lhs.width != rhs.width {
361 return Err(BitVecError::MismatchedWidths("urem".into()));
362 };
363 if rhs.v == BigUint::ZERO {
364 Ok(lhs.clone())
365 } else {
366 Ok(BitVec::of_nat(lhs.width, &lhs.v % &rhs.v))
367 }
368 }
369
370 pub fn sdiv(lhs: &Self, rhs: &Self) -> Result<Self> {
377 if lhs.width != rhs.width {
378 return Err(BitVecError::MismatchedWidths("sdiv".into()));
379 };
380 let lhs_msb = lhs.msb();
381 let rhs_msb = rhs.msb();
382
383 if !lhs_msb && !rhs_msb {
384 BitVec::udiv(lhs, rhs)
385 } else if lhs_msb && !rhs_msb {
386 Ok(BitVec::neg(&BitVec::udiv(&BitVec::neg(lhs), rhs)?))
387 } else if !lhs_msb && rhs_msb {
388 Ok(BitVec::neg(&BitVec::udiv(lhs, &BitVec::neg(rhs))?))
389 } else {
390 BitVec::udiv(&BitVec::neg(lhs), &BitVec::neg(rhs))
391 }
392 }
393
394 pub fn srem(lhs: &Self, rhs: &Self) -> Result<Self> {
401 if lhs.width != rhs.width {
402 return Err(BitVecError::MismatchedWidths("srem".into()));
403 };
404 let lhs_msb = lhs.msb();
405 let rhs_msb = rhs.msb();
406
407 if !lhs_msb && !rhs_msb {
408 BitVec::urem(lhs, rhs)
409 } else if lhs_msb && !rhs_msb {
410 Ok(BitVec::neg(&BitVec::urem(&BitVec::neg(lhs), rhs)?))
411 } else if !lhs_msb && rhs_msb {
412 BitVec::urem(lhs, &BitVec::neg(rhs))
413 } else {
414 Ok(BitVec::neg(&BitVec::urem(
415 &BitVec::neg(lhs),
416 &BitVec::neg(rhs),
417 )?))
418 }
419 }
420
421 pub fn smod(lhs: &Self, rhs: &Self) -> Result<Self> {
428 if lhs.width != rhs.width {
429 return Err(BitVecError::MismatchedWidths("smod".into()));
430 };
431 let lhs_msb = lhs.msb();
432 let rhs_msb = rhs.msb();
433
434 let abs_lhs = if !lhs_msb { lhs } else { &BitVec::neg(lhs) };
435
436 let abs_rhs = if !rhs_msb { rhs } else { &BitVec::neg(rhs) };
437
438 let u = BitVec::urem(abs_lhs, abs_rhs)?;
439 if u.is_zero() || (!lhs_msb && !rhs_msb) {
440 Ok(u)
441 } else if lhs_msb && !rhs_msb {
442 BitVec::add(&BitVec::neg(&u), rhs)
443 } else if !lhs_msb && rhs_msb {
444 BitVec::add(&u, rhs)
445 } else {
446 Ok(BitVec::neg(&u))
447 }
448 }
449
450 pub fn shl(lhs: &Self, rhs: &Self) -> Result<Self> {
455 if lhs.width != rhs.width {
456 return Err(BitVecError::MismatchedWidths("shl".into()));
457 };
458 let shift_amount = rhs.v.to_u32().ok_or(BitVecError::ShiftAmountTooLarge)?;
459 let val = &lhs.v * TWO.pow(shift_amount);
460 Ok(BitVec::of_nat(lhs.width, val))
461 }
462
463 pub fn lshr(lhs: &Self, rhs: &Self) -> Result<Self> {
468 if lhs.width != rhs.width {
469 return Err(BitVecError::MismatchedWidths("lshr".into()));
470 };
471 let shift_amount = rhs.v.to_u32().ok_or(BitVecError::ShiftAmountTooLarge)?;
472 let val = &lhs.v / TWO.pow(shift_amount);
473 Ok(BitVec::of_nat(lhs.width, val))
474 }
475
476 pub fn concat(lhs: &Self, rhs: &Self) -> Result<Self> {
482 #[expect(
483 clippy::expect_used,
484 reason = "Function is documented to panic if total width exceeds u32::MAX"
485 )]
486 let width = lhs
487 .width
488 .checked_add(rhs.width.get())
489 .expect("width will not overflow u32");
490 let new_val = (&lhs.v << rhs.width().get()) + &rhs.v;
491 Ok(BitVec::of_nat(width, new_val))
492 }
493
494 pub fn zero_extend(bv: &Self, n: Width) -> Self {
501 BitVec::of_nat(n, bv.to_nat())
502 }
503}
504
505impl std::fmt::Display for BitVec {
506 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507 write!(f, "(bv{} {})", self.width(), self.as_nat())
508 }
509}
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514
515 fn from_bin_str(s: &str) -> BitVec {
518 assert!(!s.is_empty(), "Cannot create bitvector from empty string.");
519 for c in s.chars() {
521 assert!(
522 c == '0' || c == '1',
523 "Binary string must only contain '0' or '1'"
524 );
525 }
526
527 let val = BigUint::parse_bytes(s.as_bytes(), 2).unwrap();
529 BitVec::of_nat(
530 Width::new(s.len().try_into().unwrap())
531 .expect("already checked that the string length is not 0"),
532 val,
533 )
534 }
535
536 #[track_caller]
538 fn bitvec(width: u32, val: u128) -> BitVec {
539 BitVec::of_u128(Width::new(width).unwrap(), val)
540 }
541
542 #[track_caller]
544 fn bitvec_i(width: u32, val: i128) -> BitVec {
545 BitVec::of_i128(Width::new(width).unwrap(), val)
546 }
547
548 #[track_caller]
549 fn assert_eq_int(rhs: BigInt, lhs: i32) {
550 assert_eq!(rhs, BigInt::from(lhs));
551 }
552
553 #[track_caller]
554 fn assert_eq_nat(rhs: BigUint, lhs: u32) {
555 assert_eq!(rhs, BigUint::from(lhs));
556 }
557
558 #[test]
559 fn test_from_bin_str() {
560 let bv = from_bin_str("0010");
562 assert_eq!(bv.width().get(), 4);
563 assert_eq_nat(bv.to_nat(), 2);
564
565 assert_eq_nat(from_bin_str("101").to_nat(), 5);
567 assert_eq_nat(from_bin_str("1111").to_nat(), 15);
568 assert_eq_nat(from_bin_str("10000").to_nat(), 16);
569 assert_eq_nat(from_bin_str("00000").to_nat(), 0);
570 }
571
572 #[test]
573 fn test_constructors() {
574 let bv1 = bitvec(4, 2);
576 assert_eq!(bv1.width().get(), 4);
577 assert_eq_nat(bv1.to_nat(), 2);
578
579 let bv2 = bitvec(3, 10); assert_eq!(bv2.width().get(), 3);
582 assert_eq_nat(bv2.to_nat(), 2);
583
584 let bv3 = bitvec(5, 10);
586 assert_eq!(bv3.width().get(), 5);
587 assert_eq_nat(bv3.to_nat(), 10);
588
589 let bv4 = bitvec_i(6, -1); assert_eq!(bv4.width().get(), 6);
592 assert_eq_nat(bv4.to_nat(), 63); assert_eq_int(bv4.to_int(), -1); assert_eq!(bv4, BitVec::all_ones(bv4.width()));
597 }
598
599 #[test]
600 fn test_extract_bits() {
601 let bv = from_bin_str("110101");
602
603 let extracted = bv.extract_bits(1, 3).unwrap(); assert_eq!(extracted.width().get(), 3);
606 assert_eq_nat(extracted.to_nat(), 2);
607
608 let bit = bv.extract_bits(5, 5).unwrap(); assert_eq!(bit.width().get(), 1);
611 assert_eq_nat(bit.to_nat(), 1);
612
613 let all = bv.extract_bits(0, 5).unwrap(); assert_eq!(all.width().get(), 6);
616 assert_eq_nat(all.to_nat(), 53); }
618
619 #[test]
620 fn test_bitwise_ops() {
621 let bv = from_bin_str("1010");
623 let not_bv = bv.not();
624 assert_eq_nat(not_bv.to_nat(), 5);
626 assert_eq!(not_bv.not(), bv);
627 }
628
629 #[test]
630 fn test_arithmetic_ops() {
631 let bv = from_bin_str("1010");
632 assert_eq_int(bv.to_int(), -6);
633 let neg_bv = bv.neg();
635 assert_eq_nat(neg_bv.to_nat(), 6);
637
638 let bv_min = from_bin_str("1000");
639 assert_eq!(bv_min, bv_min.neg());
640
641 let bv1 = from_bin_str("0101"); let bv2: BitVec = from_bin_str("0011"); let bv3: BitVec = from_bin_str("1011"); let sum = BitVec::add(&bv1, &bv2).unwrap();
647 assert_eq_nat(sum.to_nat(), 8); let sum = BitVec::add(&bv1, &bv3).unwrap();
651 assert_eq_nat(sum.to_nat(), 0); let diff = BitVec::sub(&bv1, &bv2).unwrap();
655 assert_eq_nat(diff.to_nat(), 2); let diff = BitVec::sub(&bv2, &bv1).unwrap();
659 assert_eq_int(diff.to_int(), -2); let prod = BitVec::mul(&bv1, &bv2).unwrap();
663 assert_eq_nat(prod.to_nat(), 15); let prod = BitVec::mul(&bv2, &bv3).unwrap();
667 assert_eq_nat(prod.to_nat(), 1); }
669
670 #[test]
671 fn test_division() {
672 let bv1 = from_bin_str("0101"); let bv2: BitVec = from_bin_str("0011"); let quot = BitVec::udiv(&bv1, &bv2).unwrap();
677 assert_eq_nat(quot.to_nat(), 1); let rem = BitVec::urem(&bv1, &bv2).unwrap();
680 assert_eq_nat(rem.to_nat(), 2); let zero = bitvec(4, 0);
684 let div_by_zero = BitVec::udiv(&bv1, &zero).unwrap();
685 assert_eq_nat(div_by_zero.to_nat(), 15); let rem_by_zero = BitVec::urem(&bv1, &zero).unwrap();
688 assert_eq!(rem_by_zero.to_nat(), bv1.to_nat());
689
690 let quot = BitVec::sdiv(&bv1, &bv2).unwrap();
694 assert_eq_nat(quot.to_nat(), 1); let srem = BitVec::srem(&bv1, &bv2).unwrap();
696 assert_eq_int(srem.to_int(), 2);
697 let smod = BitVec::smod(&bv1, &bv2).unwrap();
698 assert_eq_int(smod.to_int(), 2);
699
700 let neg_bv1 = from_bin_str("1011"); let pos_bv2 = from_bin_str("0011"); let quot_neg_pos = BitVec::sdiv(&neg_bv1, &pos_bv2).unwrap();
706 assert_eq_int(quot_neg_pos.to_int(), -1);
707
708 let srem_neg_pos = BitVec::srem(&neg_bv1, &pos_bv2).unwrap();
710 assert_eq_int(srem_neg_pos.to_int(), -2);
711
712 let smod_neg_pos = BitVec::smod(&neg_bv1, &pos_bv2).unwrap();
714 assert_eq_int(smod_neg_pos.to_int(), 1);
715
716 let int_min = from_bin_str("1000"); let quot_min_pos = BitVec::sdiv(&int_min, &pos_bv2).unwrap();
719 assert_eq_int(quot_min_pos.to_int(), -2); let srem_min_pos = BitVec::srem(&int_min, &pos_bv2).unwrap();
722 assert_eq_int(srem_min_pos.to_int(), -2); let smod_min_pos = BitVec::smod(&int_min, &pos_bv2).unwrap();
725 assert_eq_int(smod_min_pos.to_int(), 1); let pos_bv1 = from_bin_str("0101"); let neg_bv2 = from_bin_str("1101"); let quot_pos_neg = BitVec::sdiv(&pos_bv1, &neg_bv2).unwrap();
733 assert_eq_int(quot_pos_neg.to_int(), -1);
734
735 let srem_pos_neg = BitVec::srem(&pos_bv1, &neg_bv2).unwrap();
737 assert_eq_int(srem_pos_neg.to_int(), 2);
738
739 let smod_pos_neg = BitVec::smod(&pos_bv1, &neg_bv2).unwrap();
741 assert_eq_int(smod_pos_neg.to_int(), -1);
742
743 let pos_bv7 = from_bin_str("0111"); let quot_7_neg3 = BitVec::sdiv(&pos_bv7, &neg_bv2).unwrap();
746 assert_eq_int(quot_7_neg3.to_int(), -2); let srem_7_neg3 = BitVec::srem(&pos_bv7, &neg_bv2).unwrap();
749 assert_eq_int(srem_7_neg3.to_int(), 1); let smod_7_neg3 = BitVec::smod(&pos_bv7, &neg_bv2).unwrap();
752 assert_eq_int(smod_7_neg3.to_int(), -2); let neg_bv5 = from_bin_str("1011"); let neg_bv3 = from_bin_str("1101"); let quot_neg_neg = BitVec::sdiv(&neg_bv5, &neg_bv3).unwrap();
760 assert_eq_int(quot_neg_neg.to_int(), 1);
761
762 let srem_neg_neg = BitVec::srem(&neg_bv5, &neg_bv3).unwrap();
764 assert_eq_int(srem_neg_neg.to_int(), -2);
765
766 let smod_neg_neg = BitVec::smod(&neg_bv5, &neg_bv3).unwrap();
768 assert_eq_int(smod_neg_neg.to_int(), -2);
769
770 let quot_min_neg = BitVec::sdiv(&int_min, &neg_bv3).unwrap();
772 assert_eq_int(quot_min_neg.to_int(), 2); let srem_min_neg = BitVec::srem(&int_min, &neg_bv3).unwrap();
775 assert_eq_int(srem_min_neg.to_int(), -2); let smod_min_neg = BitVec::smod(&int_min, &neg_bv3).unwrap();
778 assert_eq_int(smod_min_neg.to_int(), -2); let neg_one = from_bin_str("1111"); let quot_min_neg1 = BitVec::sdiv(&int_min, &neg_one).unwrap();
783 assert_eq_int(quot_min_neg1.to_int(), -8); let srem_min_neg1 = BitVec::srem(&int_min, &neg_one).unwrap();
786 assert_eq_int(srem_min_neg1.to_int(), 0); let smod_min_neg1 = BitVec::smod(&int_min, &neg_one).unwrap();
789 assert_eq_int(smod_min_neg1.to_int(), 0); let div_by_zero = BitVec::sdiv(&bv1, &zero).unwrap();
793 assert_eq_nat(div_by_zero.to_nat(), 15); let div_by_zero_neg = BitVec::sdiv(&neg_bv1, &zero).unwrap();
797 assert_eq_nat(div_by_zero_neg.to_nat(), 1); let srem_by_zero = BitVec::srem(&bv1, &zero).unwrap();
800 assert_eq!(srem_by_zero.to_nat(), bv1.to_nat()); let smod_by_zero = BitVec::smod(&bv1, &zero).unwrap();
803 assert_eq!(smod_by_zero.to_nat(), bv1.to_nat()); }
805
806 #[test]
807 fn test_comparison_ops() {
808 let bv1 = from_bin_str("0101"); let bv2 = from_bin_str("0011"); assert!(!BitVec::slt(&bv1, &bv2).unwrap()); assert!(BitVec::slt(&bv2, &bv1).unwrap()); assert!(!BitVec::sle(&bv1, &bv2).unwrap()); assert!(BitVec::sle(&bv2, &bv1).unwrap()); assert!(BitVec::sle(&bv1, &bv1).unwrap()); let zero = from_bin_str("0000"); let neg_5 = from_bin_str("1011"); let neg_3: BitVec = from_bin_str("1101"); let neg_8: BitVec = from_bin_str("1000"); let one: BitVec = from_bin_str("0001"); assert!(BitVec::ult(&neg_5, &neg_3).unwrap());
828 assert!(BitVec::ult(&one, &neg_8).unwrap());
829 assert!(BitVec::slt(&neg_5, &neg_3).unwrap());
830 assert!(BitVec::slt(&neg_5, &zero).unwrap());
831 }
832
833 #[test]
834 fn test_shift_ops() {
835 let bv1 = from_bin_str("0101"); let shift1 = from_bin_str("0001"); let shift2 = from_bin_str("0010"); let left_shift1 = BitVec::shl(&bv1, &shift1).unwrap(); assert_eq_nat(left_shift1.to_nat(), 10);
842
843 let left_shift2 = BitVec::shl(&bv1, &shift2).unwrap(); assert_eq_nat(left_shift2.to_nat(), 4);
845
846 let bv2 = from_bin_str("1100"); let right_shift1 = BitVec::lshr(&bv2, &shift1).unwrap(); assert_eq_nat(right_shift1.to_nat(), 6);
850
851 let right_shift2 = BitVec::lshr(&bv2, &shift2).unwrap(); assert_eq_nat(right_shift2.to_nat(), 3);
853 }
854
855 #[test]
856 fn test_concat() {
857 let bv1 = from_bin_str("101"); let bv2 = from_bin_str("11"); let concat1 = BitVec::concat(&bv1, &bv2).unwrap(); assert_eq!(concat1.width().get(), 5); assert_eq_nat(concat1.to_nat(), 23);
863
864 let concat2 = BitVec::concat(&bv2, &bv1).unwrap(); assert_eq!(concat2.width().get(), 5); assert_eq_nat(concat2.to_nat(), 29);
867 }
868
869 #[test]
870 fn test_zero_extend() {
871 let bv = from_bin_str("101"); let extended1 = BitVec::zero_extend(&bv, Width::new(3).unwrap());
875 assert_eq!(extended1.width().get(), 3);
876 assert_eq_nat(extended1.to_nat(), 5);
877
878 let extended2 = BitVec::zero_extend(&bv, Width::new(2).unwrap());
880 assert_eq!(extended2.width().get(), 2);
881 assert_eq_nat(extended2.to_nat(), 1); }
883
884 #[test]
885 fn test_overflow() {
886 assert_eq!(BitVec::signed_min(Width::new(4).unwrap()), BigInt::from(-8)); assert_eq!(BitVec::signed_max(Width::new(4).unwrap()), BigInt::from(7)); assert!(BitVec::overflows(Width::new(4).unwrap(), &BigInt::from(8))); assert!(BitVec::overflows(Width::new(4).unwrap(), &BigInt::from(-9))); assert!(!BitVec::overflows(Width::new(4).unwrap(), &BigInt::from(7))); assert!(!BitVec::overflows(
895 Width::new(4).unwrap(),
896 &BigInt::from(-8)
897 )); let min = BitVec::int_min(Width::new(4).unwrap());
901 assert_eq!(min.width().get(), 4);
902 assert_eq_nat(min.to_nat(), 8); }
904}