xlsynth/
ir_value.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use xlsynth_sys::{CIrBits, CIrValue};
4
5use crate::{
6    lib_support::{
7        xls_bits_make_sbits, xls_bits_make_ubits, xls_bits_to_debug_str, xls_bits_to_string,
8        xls_format_preference_from_string, xls_value_eq, xls_value_free, xls_value_get_bits,
9        xls_value_get_element, xls_value_get_element_count, xls_value_make_array,
10        xls_value_make_sbits, xls_value_make_tuple, xls_value_make_ubits, xls_value_to_string,
11        xls_value_to_string_format_preference,
12    },
13    xls_parse_typed_value,
14    xlsynth_error::XlsynthError,
15};
16
17pub struct IrBits {
18    #[allow(dead_code)]
19    pub(crate) ptr: *mut CIrBits,
20}
21
22impl IrBits {
23    pub fn make_ubits(bit_count: usize, value: u64) -> Result<Self, XlsynthError> {
24        xls_bits_make_ubits(bit_count, value)
25    }
26
27    pub fn make_sbits(bit_count: usize, value: i64) -> Result<Self, XlsynthError> {
28        xls_bits_make_sbits(bit_count, value)
29    }
30
31    pub fn get_bit_count(&self) -> usize {
32        let bit_count = unsafe { xlsynth_sys::xls_bits_get_bit_count(self.ptr) };
33        assert!(bit_count >= 0);
34        bit_count as usize
35    }
36
37    pub fn to_debug_str(&self) -> String {
38        xls_bits_to_debug_str(self.ptr)
39    }
40
41    pub fn get_bit(&self, index: usize) -> Result<bool, XlsynthError> {
42        if self.get_bit_count() <= index {
43            return Err(XlsynthError(format!(
44                "Index {} out of bounds for bits[{}]:{}",
45                index,
46                self.get_bit_count(),
47                self.to_debug_str()
48            )));
49        }
50        let bit = unsafe { xlsynth_sys::xls_bits_get_bit(self.ptr, index as i64) };
51        Ok(bit)
52    }
53
54    pub fn to_string_fmt(&self, format: IrFormatPreference, include_bit_count: bool) -> String {
55        let fmt_pref: xlsynth_sys::XlsFormatPreference =
56            xls_format_preference_from_string(format.to_string()).unwrap();
57        xls_bits_to_string(self.ptr, fmt_pref, include_bit_count).unwrap()
58    }
59
60    #[allow(dead_code)]
61    fn to_hex_string(&self) -> String {
62        let value = self.to_string_fmt(IrFormatPreference::Hex, false);
63        format!("bits[{}]:{}", self.get_bit_count(), value)
64    }
65
66    pub fn umul(&self, rhs: &IrBits) -> IrBits {
67        let result = unsafe { xlsynth_sys::xls_bits_umul(self.ptr, rhs.ptr) };
68        IrBits { ptr: result }
69    }
70
71    pub fn smul(&self, rhs: &IrBits) -> IrBits {
72        let result = unsafe { xlsynth_sys::xls_bits_smul(self.ptr, rhs.ptr) };
73        IrBits { ptr: result }
74    }
75
76    pub fn negate(&self) -> IrBits {
77        let result = unsafe { xlsynth_sys::xls_bits_negate(self.ptr) };
78        IrBits { ptr: result }
79    }
80
81    pub fn abs(&self) -> IrBits {
82        let result = unsafe { xlsynth_sys::xls_bits_abs(self.ptr) };
83        IrBits { ptr: result }
84    }
85
86    pub fn msb(&self) -> bool {
87        self.get_bit(self.get_bit_count() - 1).unwrap()
88    }
89
90    pub fn shll(&self, shift_amount: i64) -> IrBits {
91        let result = unsafe { xlsynth_sys::xls_bits_shift_left_logical(self.ptr, shift_amount) };
92        IrBits { ptr: result }
93    }
94
95    pub fn shrl(&self, shift_amount: i64) -> IrBits {
96        let result = unsafe { xlsynth_sys::xls_bits_shift_right_logical(self.ptr, shift_amount) };
97        IrBits { ptr: result }
98    }
99
100    pub fn shra(&self, shift_amount: i64) -> IrBits {
101        let result =
102            unsafe { xlsynth_sys::xls_bits_shift_right_arithmetic(self.ptr, shift_amount) };
103        IrBits { ptr: result }
104    }
105
106    pub fn width_slice(&self, start: i64, width: i64) -> IrBits {
107        let result = unsafe { xlsynth_sys::xls_bits_width_slice(self.ptr, start, width) };
108        IrBits { ptr: result }
109    }
110
111    pub fn not(&self) -> IrBits {
112        let result = unsafe { xlsynth_sys::xls_bits_not(self.ptr) };
113        IrBits { ptr: result }
114    }
115
116    pub fn and(&self, rhs: &IrBits) -> IrBits {
117        let result = unsafe { xlsynth_sys::xls_bits_and(self.ptr, rhs.ptr) };
118        IrBits { ptr: result }
119    }
120
121    pub fn or(&self, rhs: &IrBits) -> IrBits {
122        let result = unsafe { xlsynth_sys::xls_bits_or(self.ptr, rhs.ptr) };
123        IrBits { ptr: result }
124    }
125
126    pub fn xor(&self, rhs: &IrBits) -> IrBits {
127        let result = unsafe { xlsynth_sys::xls_bits_xor(self.ptr, rhs.ptr) };
128        IrBits { ptr: result }
129    }
130}
131
132impl Drop for IrBits {
133    fn drop(&mut self) {
134        unsafe { xlsynth_sys::xls_bits_free(self.ptr) }
135    }
136}
137
138impl std::cmp::PartialEq for IrBits {
139    fn eq(&self, other: &Self) -> bool {
140        unsafe { xlsynth_sys::xls_bits_eq(self.ptr, other.ptr) }
141    }
142}
143
144impl std::fmt::Debug for IrBits {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        write!(f, "{}", self.to_debug_str())
147    }
148}
149
150impl From<&IrBits> for IrValue {
151    fn from(bits: &IrBits) -> Self {
152        IrValue::from_bits(bits)
153    }
154}
155
156impl std::fmt::Display for IrBits {
157    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158        write!(
159            f,
160            "bits[{}]:{}",
161            self.get_bit_count(),
162            self.to_string_fmt(IrFormatPreference::Default, false)
163        )
164    }
165}
166
167impl std::ops::Add for IrBits {
168    type Output = Self;
169
170    fn add(self, rhs: Self) -> Self::Output {
171        let result = unsafe { xlsynth_sys::xls_bits_add(self.ptr, rhs.ptr) };
172        Self { ptr: result }
173    }
174}
175
176impl std::ops::BitAnd for IrBits {
177    type Output = Self;
178
179    fn bitand(self, rhs: Self) -> Self::Output {
180        let result = unsafe { xlsynth_sys::xls_bits_and(self.ptr, rhs.ptr) };
181        Self { ptr: result }
182    }
183}
184
185impl std::ops::BitOr for IrBits {
186    type Output = Self;
187
188    fn bitor(self, rhs: Self) -> Self::Output {
189        IrBits::or(&self, &rhs)
190    }
191}
192
193impl std::ops::BitXor for IrBits {
194    type Output = Self;
195
196    fn bitxor(self, rhs: Self) -> Self::Output {
197        IrBits::xor(&self, &rhs)
198    }
199}
200
201impl std::ops::Not for IrBits {
202    type Output = Self;
203
204    fn not(self) -> Self::Output {
205        IrBits::not(&self)
206    }
207}
208
209// --
210
211pub enum IrFormatPreference {
212    Default,
213    Binary,
214    SignedDecimal,
215    UnsignedDecimal,
216    Hex,
217    PlainBinary,
218    ZeroPaddedBinary,
219    PlainHex,
220    ZeroPaddedHex,
221}
222
223impl IrFormatPreference {
224    pub fn to_string(&self) -> &'static str {
225        match self {
226            IrFormatPreference::Default => "default",
227            IrFormatPreference::Binary => "binary",
228            IrFormatPreference::SignedDecimal => "signed_decimal",
229            IrFormatPreference::UnsignedDecimal => "unsigned_decimal",
230            IrFormatPreference::Hex => "hex",
231            IrFormatPreference::PlainBinary => "plain_binary",
232            IrFormatPreference::ZeroPaddedBinary => "zero_padded_binary",
233            IrFormatPreference::PlainHex => "plain_hex",
234            IrFormatPreference::ZeroPaddedHex => "zero_padded_hex",
235        }
236    }
237}
238
239pub struct IrValue {
240    pub(crate) ptr: *mut CIrValue,
241}
242
243impl IrValue {
244    pub fn make_tuple(elements: &[IrValue]) -> Self {
245        xls_value_make_tuple(elements)
246    }
247
248    /// Returns an error if the elements do not all have the same type.
249    pub fn make_array(elements: &[IrValue]) -> Result<Self, XlsynthError> {
250        xls_value_make_array(elements)
251    }
252
253    pub fn from_bits(bits: &IrBits) -> Self {
254        let ptr = unsafe { xlsynth_sys::xls_value_from_bits(bits.ptr) };
255        Self { ptr }
256    }
257
258    pub fn parse_typed(s: &str) -> Result<Self, XlsynthError> {
259        xls_parse_typed_value(s)
260    }
261
262    pub fn bool(value: bool) -> Self {
263        xls_value_make_ubits(value as u64, 1).unwrap()
264    }
265
266    pub fn u32(value: u32) -> Self {
267        // Unwrap should be ok since the u32 always fits.
268        xls_value_make_ubits(value as u64, 32).unwrap()
269    }
270
271    pub fn u64(value: u64) -> Self {
272        // Unwrap should be ok since the u64 always fits.
273        xls_value_make_ubits(value as u64, 64).unwrap()
274    }
275
276    pub fn make_ubits(bit_count: usize, value: u64) -> Result<Self, XlsynthError> {
277        xls_value_make_ubits(value as u64, bit_count)
278    }
279
280    pub fn make_sbits(bit_count: usize, value: i64) -> Result<Self, XlsynthError> {
281        xls_value_make_sbits(value, bit_count)
282    }
283
284    pub fn bit_count(&self) -> Result<usize, XlsynthError> {
285        // TODO(cdleary): 2024-06-23 Expose a more efficient API for this from libxls.so
286        let bits = self.to_bits()?;
287        Ok(bits.get_bit_count())
288    }
289
290    pub fn to_string_fmt(&self, format: IrFormatPreference) -> Result<String, XlsynthError> {
291        let fmt_pref: xlsynth_sys::XlsFormatPreference =
292            xls_format_preference_from_string(format.to_string())?;
293        xls_value_to_string_format_preference(self.ptr, fmt_pref)
294    }
295
296    pub fn to_string_fmt_no_prefix(
297        &self,
298        format: IrFormatPreference,
299    ) -> Result<String, XlsynthError> {
300        let s = self.to_string_fmt(format)?;
301        if s.starts_with("bits[") {
302            let parts: Vec<&str> = s.split(':').collect();
303            Ok(parts[1].to_string())
304        } else {
305            Ok(s)
306        }
307    }
308
309    pub fn to_bool(&self) -> Result<bool, XlsynthError> {
310        let bits = self.to_bits()?;
311        if bits.get_bit_count() != 1 {
312            return Err(XlsynthError(format!(
313                "IrValue {} is not single-bit; must be bits[1] to convert to bool",
314                self.to_string()
315            )));
316        }
317        bits.get_bit(0)
318    }
319
320    pub fn to_i64(&self) -> Result<i64, XlsynthError> {
321        let string = self.to_string_fmt(IrFormatPreference::SignedDecimal)?;
322        let number = string.split(':').nth(1).expect("split success");
323        match number.parse::<i64>() {
324            Ok(i) => Ok(i),
325            Err(e) => Err(XlsynthError(format!(
326                "IrValue::to_i64() failed to parse i64 from string: {}",
327                e
328            ))),
329        }
330    }
331
332    pub fn to_u64(&self) -> Result<u64, XlsynthError> {
333        let string = self.to_string_fmt(IrFormatPreference::UnsignedDecimal)?;
334        let number = string.split(':').nth(1).expect("split success");
335        match number.parse::<u64>() {
336            Ok(i) => Ok(i),
337            Err(e) => Err(XlsynthError(format!(
338                "IrValue::to_u64() failed to parse u64 from string: {}",
339                e
340            ))),
341        }
342    }
343
344    pub fn to_u32(&self) -> Result<u32, XlsynthError> {
345        let string = self.to_string_fmt(IrFormatPreference::UnsignedDecimal)?;
346        let number = string.split(':').nth(1).expect("split success");
347        match number.parse::<u32>() {
348            Ok(i) => Ok(i),
349            Err(e) => Err(XlsynthError(format!(
350                "IrValue::to_u32() failed to parse u32 from string: {}",
351                e
352            ))),
353        }
354    }
355
356    /// Attempts to extract the bits contents underlying this value.
357    ///
358    /// If this value is not a bits type, an error is returned.
359    pub fn to_bits(&self) -> Result<IrBits, XlsynthError> {
360        xls_value_get_bits(self.ptr)
361    }
362
363    pub fn get_element(&self, index: usize) -> Result<IrValue, XlsynthError> {
364        xls_value_get_element(self.ptr, index)
365    }
366
367    pub fn get_element_count(&self) -> Result<usize, XlsynthError> {
368        xls_value_get_element_count(self.ptr)
369    }
370
371    pub fn get_elements(&self) -> Result<Vec<IrValue>, XlsynthError> {
372        let count = self.get_element_count()?;
373        let mut elements = Vec::with_capacity(count);
374        for i in 0..count {
375            let element = self.get_element(i)?;
376            elements.push(element);
377        }
378        Ok(elements)
379    }
380}
381
382unsafe impl Send for IrValue {}
383unsafe impl Sync for IrValue {}
384
385impl Into<IrValue> for bool {
386    fn into(self) -> IrValue {
387        IrValue::bool(self)
388    }
389}
390
391impl Into<IrValue> for u32 {
392    fn into(self) -> IrValue {
393        IrValue::u32(self)
394    }
395}
396
397impl Into<IrValue> for u64 {
398    fn into(self) -> IrValue {
399        IrValue::u64(self)
400    }
401}
402
403impl std::cmp::PartialEq for IrValue {
404    fn eq(&self, other: &Self) -> bool {
405        xls_value_eq(self.ptr, other.ptr).expect("eq success")
406    }
407}
408
409impl std::fmt::Display for IrValue {
410    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
411        write!(
412            f,
413            "{}",
414            xls_value_to_string(self.ptr).expect("stringify success")
415        )
416    }
417}
418
419impl std::fmt::Debug for IrValue {
420    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
421        write!(
422            f,
423            "{}",
424            xls_value_to_string(self.ptr).expect("stringify success")
425        )
426    }
427}
428
429impl Drop for IrValue {
430    fn drop(&mut self) {
431        xls_value_free(self.ptr)
432    }
433}
434
435impl Clone for IrValue {
436    fn clone(&self) -> Self {
437        let ptr = unsafe { xlsynth_sys::xls_value_clone(self.ptr) };
438        Self { ptr }
439    }
440}
441
442/// Typed wrapper around an `IrBits` value that has a particular
443/// compile-time-known bit width and whose type notes the value
444/// should be treated as unsigned.
445pub struct IrUBits<const BIT_COUNT: usize> {
446    #[allow(dead_code)]
447    wrapped: IrBits,
448}
449
450impl<const BIT_COUNT: usize> IrUBits<BIT_COUNT> {
451    pub const SIGNEDNESS: bool = false;
452
453    pub fn new(wrapped: IrBits) -> Result<Self, XlsynthError> {
454        if wrapped.get_bit_count() != BIT_COUNT {
455            return Err(XlsynthError(format!(
456                "Expected {} bits, got {}",
457                BIT_COUNT,
458                wrapped.get_bit_count()
459            )));
460        }
461        Ok(Self { wrapped })
462    }
463}
464
465/// Typed wrapper around an `IrBits` value that has a particular
466/// compile-time-known bit width and whose type notes the value
467/// should be treated as signed.
468pub struct IrSBits<const BIT_COUNT: usize> {
469    #[allow(dead_code)]
470    wrapped: IrBits,
471}
472
473impl<const BIT_COUNT: usize> IrSBits<BIT_COUNT> {
474    pub const SIGNEDNESS: bool = true;
475
476    pub fn new(wrapped: IrBits) -> Result<Self, XlsynthError> {
477        if wrapped.get_bit_count() != BIT_COUNT {
478            return Err(XlsynthError(format!(
479                "Expected {} bits, got {}",
480                BIT_COUNT,
481                wrapped.get_bit_count()
482            )));
483        }
484        Ok(Self { wrapped })
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    use super::*;
491
492    #[test]
493    fn test_ir_value_eq() {
494        let v1 = IrValue::parse_typed("bits[32]:42").expect("parse success");
495        let v2 = IrValue::parse_typed("bits[32]:42").expect("parse success");
496        assert_eq!(v1, v2);
497    }
498
499    #[test]
500    fn test_ir_value_eq_fail() {
501        let v1 = IrValue::parse_typed("bits[32]:42").expect("parse success");
502        let v2 = IrValue::parse_typed("bits[32]:43").expect("parse success");
503        assert_ne!(v1, v2);
504    }
505
506    #[test]
507    fn test_ir_value_display() {
508        let v = IrValue::parse_typed("bits[32]:42").expect("parse success");
509        assert_eq!(format!("{}", v), "bits[32]:42");
510    }
511
512    #[test]
513    fn test_ir_value_debug() {
514        let v = IrValue::parse_typed("bits[32]:42").expect("parse success");
515        assert_eq!(format!("{:?}", v), "bits[32]:42");
516    }
517
518    #[test]
519    fn test_ir_value_drop() {
520        let v = IrValue::parse_typed("bits[32]:42").expect("parse success");
521        drop(v);
522    }
523
524    #[test]
525    fn test_ir_value_fmt_pref() {
526        let v = IrValue::parse_typed("bits[32]:42").expect("parse success");
527        assert_eq!(
528            v.to_string_fmt(IrFormatPreference::Default)
529                .expect("fmt success"),
530            "bits[32]:42"
531        );
532        assert_eq!(
533            v.to_string_fmt(IrFormatPreference::Binary)
534                .expect("fmt success"),
535            "bits[32]:0b10_1010"
536        );
537        assert_eq!(
538            v.to_string_fmt(IrFormatPreference::SignedDecimal)
539                .expect("fmt success"),
540            "bits[32]:42"
541        );
542        assert_eq!(
543            v.to_string_fmt(IrFormatPreference::UnsignedDecimal)
544                .expect("fmt success"),
545            "bits[32]:42"
546        );
547        assert_eq!(
548            v.to_string_fmt(IrFormatPreference::Hex)
549                .expect("fmt success"),
550            "bits[32]:0x2a"
551        );
552        assert_eq!(
553            v.to_string_fmt(IrFormatPreference::PlainBinary)
554                .expect("fmt success"),
555            "bits[32]:101010"
556        );
557        assert_eq!(
558            v.to_string_fmt(IrFormatPreference::PlainHex)
559                .expect("fmt success"),
560            "bits[32]:2a"
561        );
562    }
563
564    #[test]
565    fn test_ir_value_from_rust() {
566        let v = IrValue::u64(42);
567
568        // Check formatting for default stringification.
569        assert_eq!(
570            v.to_string_fmt(IrFormatPreference::Default)
571                .expect("fmt success"),
572            "bits[64]:42"
573        );
574        // Check the bit count is as we specified.
575        assert_eq!(v.bit_count().unwrap(), 64);
576
577        // Check we can't convert a 64-bit value to a bool.
578        v.to_bool()
579            .expect_err("bool conversion should error for u64");
580
581        let v_i64 = v.to_i64().expect("i64 conversion success");
582        assert_eq!(v_i64, 42);
583
584        let f = IrValue::parse_typed("bits[1]:0").expect("parse success");
585        assert_eq!(f.to_bool().unwrap(), false);
586
587        let t = IrValue::parse_typed("bits[1]:1").expect("parse success");
588        assert_eq!(t.to_bool().unwrap(), true);
589    }
590
591    #[test]
592    fn test_ir_value_get_bits() {
593        let v = IrValue::parse_typed("bits[32]:42").expect("parse success");
594        let bits = v.to_bits().expect("to_bits success");
595
596        // Equality comparison.
597        let v2 = IrValue::make_ubits(32, 42).expect("make_ubits success");
598        assert_eq!(v, v2);
599
600        // Getting at bit values; 42 = 0b101010.
601        assert_eq!(bits.get_bit(0).unwrap(), false);
602        assert_eq!(bits.get_bit(1).unwrap(), true);
603        assert_eq!(bits.get_bit(2).unwrap(), false);
604        assert_eq!(bits.get_bit(3).unwrap(), true);
605        assert_eq!(bits.get_bit(4).unwrap(), false);
606        assert_eq!(bits.get_bit(5).unwrap(), true);
607        assert_eq!(bits.get_bit(6).unwrap(), false);
608        for i in 7..32 {
609            assert_eq!(bits.get_bit(i).unwrap(), false);
610        }
611        assert!(
612            bits.get_bit(32).is_err(),
613            "Expected an error for out of bounds index"
614        );
615        assert!(bits
616            .get_bit(32)
617            .unwrap_err()
618            .to_string()
619            .contains("Index 32 out of bounds for bits[32]:0b00000000000000000000000000101010"));
620
621        let debug_fmt = format!("{:?}", bits);
622        assert_eq!(debug_fmt, "0b00000000000000000000000000101010");
623    }
624
625    #[test]
626    fn test_ir_value_make_bits() {
627        let zero_u2 = IrValue::make_ubits(2, 0).expect("make_ubits success");
628        assert_eq!(
629            zero_u2
630                .to_string_fmt(IrFormatPreference::Default)
631                .expect("fmt success"),
632            "bits[2]:0"
633        );
634
635        let three_u2 = IrValue::make_ubits(2, 3).expect("make_ubits success");
636        assert_eq!(
637            three_u2
638                .to_string_fmt(IrFormatPreference::Default)
639                .expect("fmt success"),
640            "bits[2]:3"
641        );
642    }
643
644    #[test]
645    fn test_ir_value_parse_array_value() {
646        let text = "[bits[32]:1, bits[32]:2]";
647        let v = IrValue::parse_typed(text).expect("parse success");
648        assert_eq!(v.to_string(), text);
649    }
650
651    #[test]
652    fn test_ir_value_parse_2d_array_value() {
653        let text = "[[bits[32]:1, bits[32]:2], [bits[32]:3, bits[32]:4], [bits[32]:5, bits[32]:6]]";
654        let v = IrValue::parse_typed(text).expect("parse success");
655        assert_eq!(v.to_string(), text);
656    }
657
658    #[test]
659    fn test_ir_bits_add_two_plus_three() {
660        let two = IrBits::make_ubits(32, 2).expect("make_ubits success");
661        let three = IrBits::make_ubits(32, 3).expect("make_ubits success");
662        let sum = two + three;
663        assert_eq!(sum.to_string(), "bits[32]:5");
664    }
665
666    #[test]
667    fn test_ir_bits_umul_two_times_three() {
668        let two = IrBits::make_ubits(32, 2).expect("make_ubits success");
669        let three = IrBits::make_ubits(32, 3).expect("make_ubits success");
670        let product = two.umul(&three);
671        assert_eq!(product.to_string(), "bits[64]:6");
672    }
673
674    #[test]
675    fn test_ir_bits_smul_two_times_neg_three() {
676        let two = IrBits::make_ubits(32, 2).expect("make_ubits success");
677        let neg_three = IrBits::make_ubits(32, 3)
678            .expect("make_ubits success")
679            .negate();
680        let product = two.smul(&neg_three);
681        assert_eq!(product.msb(), true);
682        assert_eq!(product.abs().to_string(), "bits[64]:6");
683    }
684
685    #[test]
686    fn test_ir_bits_width_slice() {
687        let bits = IrBits::make_ubits(32, 0x12345678).expect("make_ubits success");
688        let slice = bits.width_slice(8, 16);
689        assert_eq!(slice.to_hex_string(), "bits[16]:0x3456");
690    }
691
692    #[test]
693    fn test_ir_bits_shll() {
694        let bits = IrBits::make_ubits(32, 0x12345678).expect("make_ubits success");
695        let shifted = bits.shll(8);
696        assert_eq!(shifted.to_hex_string(), "bits[32]:0x3456_7800");
697    }
698
699    #[test]
700    fn test_ir_bits_shrl() {
701        let bits = IrBits::make_ubits(32, 0x12345678).expect("make_ubits success");
702        let shifted = bits.shrl(8);
703        assert_eq!(shifted.to_hex_string(), "bits[32]:0x12_3456");
704    }
705
706    #[test]
707    fn test_ir_bits_shra() {
708        let bits = IrBits::make_ubits(32, 0x92345678).expect("make_ubits success");
709        let shifted = bits.shra(8);
710        assert_eq!(shifted.to_hex_string(), "bits[32]:0xff92_3456");
711    }
712
713    #[test]
714    fn test_ir_bits_and() {
715        let lhs = IrBits::make_ubits(32, 0x5a5a5a5a).expect("make_ubits success");
716        let rhs = IrBits::make_ubits(32, 0xa5a5a5a5).expect("make_ubits success");
717        assert_eq!(lhs.and(&rhs).to_hex_string(), "bits[32]:0x0");
718        assert_eq!(lhs.and(&rhs.not()).to_hex_string(), "bits[32]:0x5a5a_5a5a");
719    }
720
721    #[test]
722    fn test_ir_bits_or() {
723        let lhs = IrBits::make_ubits(32, 0x5a5a5a5a).expect("make_ubits success");
724        let rhs = IrBits::make_ubits(32, 0xa5a5a5a5).expect("make_ubits success");
725        assert_eq!(lhs.or(&rhs).to_hex_string(), "bits[32]:0xffff_ffff");
726        assert_eq!(lhs.or(&rhs.not()).to_hex_string(), "bits[32]:0x5a5a_5a5a");
727    }
728
729    #[test]
730    fn test_ir_bits_xor() {
731        let lhs = IrBits::make_ubits(32, 0x5a5a5a5a).expect("make_ubits success");
732        let rhs = IrBits::make_ubits(32, 0xa5a5a5a5).expect("make_ubits success");
733        assert_eq!(lhs.xor(&rhs).to_hex_string(), "bits[32]:0xffff_ffff");
734        assert_eq!(lhs.xor(&rhs.not()).to_hex_string(), "bits[32]:0x0");
735    }
736
737    #[test]
738    fn test_make_tuple_and_get_elements() {
739        let _ = env_logger::builder().is_test(true).try_init();
740        let b1_v0 = IrValue::make_ubits(1, 0).expect("make_ubits success");
741        let b2_v1 = IrValue::make_ubits(2, 1).expect("make_ubits success");
742        let b3_v2 = IrValue::make_ubits(3, 2).expect("make_ubits success");
743        let tuple = IrValue::make_tuple(&[b1_v0.clone(), b2_v1.clone(), b3_v2.clone()]);
744        let elements = tuple.get_elements().expect("get_elements success");
745        assert_eq!(elements.len(), 3);
746        assert_eq!(elements[0].to_string(), "bits[1]:0");
747        assert_eq!(elements[0], b1_v0);
748        assert_eq!(elements[1].to_string(), "bits[2]:1");
749        assert_eq!(elements[1], b2_v1);
750        assert_eq!(elements[2].to_string(), "bits[3]:2");
751        assert_eq!(elements[2], b3_v2);
752    }
753
754    #[test]
755    fn test_make_ir_value_bits_that_does_not_fit() {
756        let result = IrValue::make_ubits(1, 2);
757        assert!(result.is_err());
758        let error = result.unwrap_err();
759        assert!(error.to_string().contains("0x2 requires 2 bits to fit in an unsigned datatype, but attempting to fit in 1 bit"), "got: {}", error);
760
761        let result = IrValue::make_sbits(1, -2);
762        assert!(result.is_err());
763        let error = result.unwrap_err();
764        assert!(error.to_string().contains("0xfffffffffffffffe requires 2 bits to fit in an signed datatype, but attempting to fit in 1 bit"), "got: {}", error);
765    }
766
767    #[test]
768    fn test_make_ir_value_array() {
769        let b2_v0 = IrValue::make_ubits(2, 0).expect("make_ubits success");
770        let b2_v1 = IrValue::make_ubits(2, 1).expect("make_ubits success");
771        let b2_v2 = IrValue::make_ubits(2, 2).expect("make_ubits success");
772        let b2_v3 = IrValue::make_ubits(2, 3).expect("make_ubits success");
773        let array = IrValue::make_array(&[b2_v0, b2_v1, b2_v2, b2_v3]).expect("make_array success");
774        assert_eq!(
775            array.to_string(),
776            "[bits[2]:0, bits[2]:1, bits[2]:2, bits[2]:3]"
777        );
778    }
779
780    #[test]
781    fn test_make_ir_value_empty_array() {
782        IrValue::make_array(&[]).expect_err("make_array should fail for empty array");
783    }
784
785    #[test]
786    fn test_make_ir_value_array_with_mixed_types() {
787        let b2_v0 = IrValue::make_ubits(2, 0).expect("make_ubits success");
788        let b3_v1 = IrValue::make_ubits(3, 1).expect("make_ubits success");
789        let result = IrValue::make_array(&[b2_v0, b3_v1]);
790        assert!(result.is_err());
791        let error = result.unwrap_err();
792        assert!(error.to_string().contains("SameTypeAs"));
793    }
794}