spade_mir/
diff.rs

1use std::collections::HashMap;
2
3use spade_common::id_tracker::ExprID;
4
5use crate::{Entity, MirInput, Register, Statement, ValueName};
6
7macro_rules! check {
8    ($cond:expr) => {
9        if !($cond) {
10            return false;
11        }
12    };
13}
14
15/// Functions for diffing and comparing mir code while ignoring exact variable IDs
16
17pub struct VarMap {
18    pub expr_map: HashMap<ExprID, ExprID>,
19    pub expr_map_rev: HashMap<ExprID, ExprID>,
20    pub name_map: HashMap<u64, u64>,
21    pub name_map_rev: HashMap<u64, u64>,
22}
23
24impl Default for VarMap {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl VarMap {
31    pub fn new() -> Self {
32        Self {
33            expr_map: HashMap::new(),
34            expr_map_rev: HashMap::new(),
35            name_map: HashMap::new(),
36            name_map_rev: HashMap::new(),
37        }
38    }
39
40    pub fn map_expr(&mut self, lhs: ExprID, rhs: ExprID) {
41        self.expr_map.insert(lhs, rhs);
42        self.expr_map_rev.insert(rhs, lhs);
43    }
44
45    pub fn map_name(&mut self, lhs: u64, rhs: u64) {
46        self.name_map.insert(lhs, rhs);
47        self.name_map_rev.insert(rhs, lhs);
48    }
49
50    fn try_update_name(&mut self, lhs: &ValueName, rhs: &ValueName) -> Result<(), ()> {
51        // Update the name if both are the same kind
52        match (lhs, rhs) {
53            (ValueName::Named(i1, n1, _), ValueName::Named(i2, n2, _)) => {
54                if n1 != n2 {
55                    Err(())
56                } else {
57                    self.map_name(*i1, *i2);
58                    Ok(())
59                }
60            }
61            (ValueName::Expr(i1), ValueName::Expr(i2)) => {
62                self.map_expr(*i1, *i2);
63                Ok(())
64            }
65            _ => Err(()),
66        }
67    }
68
69    fn compare_name(
70        &self,
71        (lhs_id, lhs_name): (&u64, &str),
72        (rhs_id, rhs_name): (&u64, &str),
73    ) -> bool {
74        if lhs_name != rhs_name {
75            return false;
76        }
77
78        self.name_map
79            .get(lhs_id)
80            .map(|v| rhs_id == v)
81            .unwrap_or(false)
82    }
83
84    fn compare_exprs(&self, lhs: ExprID, rhs: ExprID) -> bool {
85        self.expr_map.get(&lhs).map(|v| v == &rhs).unwrap_or(false)
86    }
87
88    pub fn compare_vals(&self, lhs: &ValueName, rhs: &ValueName) -> bool {
89        match (lhs, rhs) {
90            (ValueName::Named(i1, n1, _), ValueName::Named(i2, n2, _)) => {
91                self.compare_name((i1, n1), (i2, n2))
92            }
93            (ValueName::Expr(i1), ValueName::Expr(i2)) => self.compare_exprs(*i1, *i2),
94            _ => false,
95        }
96    }
97}
98
99/// Compare statements, if they match, add the new mapping to the mapping table
100fn compare_statements(s1: &Statement, s2: &Statement, var_map: &mut VarMap) -> bool {
101    macro_rules! check_name {
102        ($lhs:expr, $rhs:expr) => {
103            if !var_map.compare_vals($lhs, $rhs) {
104                return false;
105            }
106        };
107    }
108    match (s1, s2) {
109        (Statement::Binding(b1), Statement::Binding(b2)) => {
110            // Compare the types and operators
111
112            if b1.ty != b2.ty {
113                return false;
114            }
115            if b1.operator != b2.operator {
116                return false;
117            }
118            if b1.operands.len() != b2.operands.len() {
119                return false;
120            }
121            // Check the params
122            for (n1, n2) in b1.operands.iter().zip(b2.operands.iter()) {
123                check_name!(n1, n2)
124            }
125
126            true
127        }
128        (Statement::Register(r1), Statement::Register(r2)) => {
129            let Register {
130                name: _,
131                ty: ty1,
132                clock: clock1,
133                reset: reset1,
134                initial: initial1,
135                value: value1,
136                loc: _,
137                traced: _,
138            } = &r1;
139            let Register {
140                name: _,
141                ty: ty2,
142                clock: clock2,
143                reset: reset2,
144                initial: initial2,
145                value: value2,
146                loc: _,
147                traced: _,
148            } = &r2;
149            if ty1 != ty2 {
150                return false;
151            }
152
153            check_name!(value1, value2);
154            check_name!(clock1, clock2);
155
156            match (reset1, reset2) {
157                (Some((t1, v1)), Some((t2, v2))) => {
158                    check_name!(t1, t2);
159                    check_name!(v1, v2);
160                }
161                (None, None) => {}
162                _ => return false,
163            }
164
165            match (initial1, initial2) {
166                (Some(l), Some(r)) => {
167                    if l != r {
168                        return false;
169                    }
170                }
171                (None, None) => {}
172                _ => return false,
173            }
174
175            true
176        }
177        (Statement::Constant(_, t1, v1), Statement::Constant(_, t2, v2)) => {
178            if t1 != t2 {
179                return false;
180            }
181            if v1 != v2 {
182                return false;
183            }
184            true
185        }
186        (Statement::Assert(v1), Statement::Assert(v2)) => {
187            check_name!(v1, v2);
188            true
189        }
190        (
191            Statement::Set {
192                target: tl,
193                value: vl,
194            },
195            Statement::Set {
196                target: tr,
197                value: vr,
198            },
199        ) => {
200            check_name!(tl, tr);
201            check_name!(vl, vr);
202            true
203        }
204        (
205            Statement::WalTrace {
206                name: n1,
207                val: v1,
208                suffix: s1,
209                ty: ty1,
210            },
211            Statement::WalTrace {
212                name: n2,
213                val: v2,
214                suffix: s2,
215                ty: ty2,
216            },
217        ) => {
218            check_name!(n1, n2);
219            check_name!(v1, v2);
220            if s1 != s2 {
221                return false;
222            }
223            if ty1 != ty2 {
224                return false;
225            }
226            true
227        }
228        _ => false,
229    }
230}
231
232fn populate_var_map(
233    stmts1: &[Statement],
234    stmts2: &[Statement],
235    var_map: &mut VarMap,
236) -> Result<(), ()> {
237    // Check if two names can be the same by comparing the string names of ValueName::Named.
238    // If they are the same, merge them and return true
239    stmts1
240        .iter()
241        .zip(stmts2.iter())
242        .try_for_each(|(s1, s2)| match (s1, s2) {
243            (Statement::Binding(b1), Statement::Binding(b2)) => {
244                var_map.try_update_name(&b1.name, &b2.name)
245            }
246            (Statement::Register(r1), Statement::Register(r2)) => {
247                var_map.try_update_name(&r1.name, &r2.name)
248            }
249            (Statement::Constant(e1, _, _), Statement::Constant(e2, _, _)) => {
250                var_map.try_update_name(&ValueName::Expr(*e1), &ValueName::Expr(*e2))
251            }
252            (Statement::WalTrace { .. }, Statement::WalTrace { .. }) => Ok(()),
253            (Statement::Assert(_), Statement::Assert(_)) => Ok(()),
254            (Statement::Set { .. }, Statement::Set { .. }) => Ok(()),
255            _ => Err(()),
256        })
257}
258
259pub fn compare_entity(e1: &Entity, e2: &Entity, var_map: &mut VarMap) -> bool {
260    check!(e1.name == e2.name);
261    check!(e1.output_type == e2.output_type);
262
263    for (
264        MirInput {
265            name: n1,
266            val_name: vn1,
267            ty: t1,
268            no_mangle: nm1,
269        },
270        MirInput {
271            name: n2,
272            val_name: vn2,
273            ty: t2,
274            no_mangle: nm2,
275        },
276    ) in e1.inputs.iter().zip(e2.inputs.iter())
277    {
278        check!(nm1 == nm2);
279        check!(n1 == n2);
280        check!(var_map.try_update_name(vn1, vn2).is_ok());
281        check!(t1 == t2);
282    }
283
284    if populate_var_map(&e1.statements, &e2.statements, var_map).is_err() {
285        return false;
286    }
287
288    for (s1, s2) in e1.statements.iter().zip(e2.statements.iter()) {
289        check!(compare_statements(s1, s2, var_map))
290    }
291    check!(e1.statements.len() == e2.statements.len());
292
293    check!(var_map.compare_vals(&e1.output, &e2.output));
294
295    true
296}
297
298#[cfg(test)]
299mod statement_comparison_tests {
300    use super::*;
301
302    use crate::{statement, types::Type, ConstantValue};
303
304    use crate as spade_mir;
305
306    #[test]
307    fn identical_bindings_update_expr_map() {
308        let mut map = VarMap::new();
309
310        map.map_expr(ExprID(1), ExprID(2));
311        map.map_name(2, 3);
312
313        let lhs = statement!(e(0); Type::int(5); Add; e(1), n(2, "test"));
314        let rhs = statement!(e(3); Type::int(5); Add; e(2), n(3, "test"));
315
316        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
317        assert!(compare_statements(&lhs, &rhs, &mut map));
318
319        assert!(map.compare_exprs(ExprID(0), ExprID(3)))
320    }
321
322    #[test]
323    fn identical_bindings_update_name_map() {
324        let mut map = VarMap::new();
325
326        map.map_expr(ExprID(1), ExprID(2));
327        map.map_name(2, 3);
328
329        let lhs = statement!(n(0, "a"); Type::int(5); Add; e(1), n(2, "test"));
330        let rhs = statement!(n(3, "a"); Type::int(5); Add; e(2), n(3, "test"));
331
332        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
333        assert!(compare_statements(&lhs, &rhs, &mut map));
334
335        assert!(map.compare_name((&0, "a"), (&3, "a")))
336    }
337
338    #[test]
339    fn identical_bindings_with_differing_string_name_diff() {
340        let mut map = VarMap::new();
341
342        map.map_expr(ExprID(1), ExprID(2));
343        map.map_name(2, 3);
344
345        let lhs = statement!(n(0, "a"); Type::int(5); Add; e(1), n(2, "test"));
346        let rhs = statement!(n(3, "b"); Type::int(5); Add; e(2), n(3, "test"));
347
348        assert!(populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).is_err());
349    }
350
351    #[test]
352    fn bindings_with_mismatched_types_are_different() {
353        let mut map = VarMap::new();
354
355        map.map_expr(ExprID(1), ExprID(1));
356        map.map_expr(ExprID(2), ExprID(2));
357
358        let lhs = statement!(e(0); Type::int(5); Add; e(1), e(2));
359        let rhs = statement!(e(3); Type::int(4); Add; e(1), e(2));
360
361        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
362
363        assert!(!compare_statements(&lhs, &rhs, &mut map));
364    }
365
366    #[test]
367    fn bindings_with_mismatched_operators_are_different() {
368        let mut map = VarMap::new();
369
370        map.map_expr(ExprID(1), ExprID(1));
371        map.map_expr(ExprID(2), ExprID(2));
372
373        let lhs = statement!(e(0); Type::int(5); Add; e(1), e(2));
374        let rhs = statement!(e(3); Type::int(5); Select; e(1), e(2));
375
376        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
377
378        assert!(!compare_statements(&lhs, &rhs, &mut map));
379    }
380
381    #[test]
382    fn bindings_with_mismatched_operands_are_different() {
383        let mut map = VarMap::new();
384
385        map.map_expr(ExprID(1), ExprID(1));
386        map.map_expr(ExprID(2), ExprID(2));
387
388        let lhs = statement!(e(0); Type::int(5); Add; e(2), e(1));
389        let rhs = statement!(e(3); Type::int(5); Add; e(1), e(2));
390
391        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
392
393        assert!(!compare_statements(&lhs, &rhs, &mut map));
394    }
395
396    #[test]
397    fn bindings_with_unmapped_names_are_different() {
398        let mut map = VarMap::new();
399
400        map.map_expr(ExprID(1), ExprID(1));
401        map.map_expr(ExprID(2), ExprID(2));
402
403        let lhs = statement!(e(0); Type::int(5); Add; e(2), e(1));
404        let rhs = statement!(e(3); Type::int(5); Add; e(1), e(3));
405
406        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
407
408        assert!(!compare_statements(&lhs, &rhs, &mut map));
409    }
410
411    // Register tests
412    #[test]
413    fn identical_registers_with_reset_do_not_diff() {
414        let mut map = VarMap::new();
415
416        map.map_expr(ExprID(1), ExprID(1));
417        map.map_expr(ExprID(2), ExprID(2));
418        map.map_expr(ExprID(3), ExprID(3));
419        map.map_expr(ExprID(4), ExprID(4));
420
421        let lhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
422        let rhs = statement!(reg e(5); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
423
424        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
425
426        assert!(compare_statements(&lhs, &rhs, &mut map));
427    }
428
429    #[test]
430    fn identical_registers_with_reset_do_not_diff_and_update_names() {
431        let mut map = VarMap::new();
432
433        map.map_expr(ExprID(1), ExprID(1));
434        map.map_expr(ExprID(2), ExprID(2));
435        map.map_expr(ExprID(3), ExprID(3));
436        map.map_expr(ExprID(4), ExprID(4));
437
438        let lhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
439        let rhs = statement!(reg e(5); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
440
441        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
442
443        assert!(compare_statements(&lhs, &rhs, &mut map));
444
445        assert!(map.compare_exprs(ExprID(0), ExprID(5)));
446    }
447
448    #[test]
449    fn identical_registers_update_name_table() {
450        let mut map = VarMap::new();
451
452        map.map_expr(ExprID(1), ExprID(1));
453        map.map_expr(ExprID(2), ExprID(2));
454        map.map_expr(ExprID(3), ExprID(3));
455        map.map_expr(ExprID(4), ExprID(4));
456
457        let lhs = statement!(reg n(0, "test"); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
458        let rhs = statement!(reg n(5, "test"); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
459
460        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
461
462        assert!(compare_statements(&lhs, &rhs, &mut map));
463
464        assert!(map.compare_name((&0, "test"), (&5, "test")));
465    }
466
467    #[test]
468    fn mismatched_register_clocks_causes_a_diff() {
469        let mut map = VarMap::new();
470
471        map.map_expr(ExprID(1), ExprID(1));
472        map.map_expr(ExprID(2), ExprID(2));
473        map.map_expr(ExprID(3), ExprID(3));
474        map.map_expr(ExprID(4), ExprID(4));
475
476        let lhs = statement!(reg e(0); Type::int(5); clock(e(3)); reset(e(3), e(4)); e(1));
477        let rhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
478
479        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
480
481        assert!(!compare_statements(&lhs, &rhs, &mut map));
482    }
483
484    #[test]
485    fn mismatched_register_reset_trig_causes_a_diff() {
486        let mut map = VarMap::new();
487
488        map.map_expr(ExprID(1), ExprID(1));
489        map.map_expr(ExprID(2), ExprID(2));
490        map.map_expr(ExprID(3), ExprID(3));
491        map.map_expr(ExprID(4), ExprID(4));
492
493        let lhs = statement!(reg e(0); Type::int(5); clock(e(3)); reset(e(3), e(4)); e(1));
494        let rhs = statement!(reg e(0); Type::int(5); clock(e(3)); reset(e(2), e(4)); e(1));
495
496        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
497
498        assert!(!compare_statements(&lhs, &rhs, &mut map));
499    }
500
501    #[test]
502    fn mismatched_register_value_causes_diff() {
503        let mut map = VarMap::new();
504
505        map.map_expr(ExprID(1), ExprID(1));
506        map.map_expr(ExprID(2), ExprID(2));
507        map.map_expr(ExprID(3), ExprID(3));
508        map.map_expr(ExprID(4), ExprID(4));
509
510        let lhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
511        let rhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(5)); e(1));
512
513        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
514
515        assert!(!compare_statements(&lhs, &rhs, &mut map));
516    }
517
518    #[test]
519    fn identical_registers_with_mismatched_value_diff() {
520        let mut map = VarMap::new();
521
522        map.map_expr(ExprID(1), ExprID(1));
523        map.map_expr(ExprID(2), ExprID(2));
524        map.map_expr(ExprID(3), ExprID(3));
525        map.map_expr(ExprID(4), ExprID(4));
526
527        let lhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
528        let rhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(2));
529
530        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
531
532        assert!(!compare_statements(&lhs, &rhs, &mut map));
533    }
534
535    #[test]
536    fn identical_registers_with_mismatched_initial_diff() {
537        let mut map = VarMap::new();
538
539        map.map_expr(ExprID(1), ExprID(1));
540        map.map_expr(ExprID(2), ExprID(2));
541        map.map_expr(ExprID(3), ExprID(3));
542        map.map_expr(ExprID(4), ExprID(4));
543
544        let lhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)) initial(vec![statement!(e(0); Type::Bool; Alias; e(3))]); e(1));
545        let rhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)) initial(vec![statement!(e(0); Type::Bool; Alias; e(2))]); e(1));
546
547        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
548
549        assert!(!compare_statements(&lhs, &rhs, &mut map));
550    }
551
552    #[test]
553    fn identical_registers_with_initial_is_different_from_without() {
554        let mut map = VarMap::new();
555
556        map.map_expr(ExprID(1), ExprID(1));
557        map.map_expr(ExprID(2), ExprID(2));
558        map.map_expr(ExprID(3), ExprID(3));
559        map.map_expr(ExprID(4), ExprID(4));
560
561        let lhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
562        let rhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)) initial(vec![statement!(e(0); Type::Bool; Alias; e(2))]); e(1));
563
564        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
565
566        assert!(!compare_statements(&lhs, &rhs, &mut map));
567    }
568
569    #[test]
570    fn missing_register_causes_a_diff() {
571        let mut map = VarMap::new();
572
573        map.map_expr(ExprID(1), ExprID(1));
574        map.map_expr(ExprID(2), ExprID(2));
575        map.map_expr(ExprID(3), ExprID(3));
576        map.map_expr(ExprID(4), ExprID(4));
577
578        let lhs = statement!(reg e(0); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
579        let rhs = statement!(reg e(0); Type::int(5); clock(e(2)); e(1));
580
581        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
582
583        assert!(!compare_statements(&lhs, &rhs, &mut map));
584    }
585
586    #[test]
587    fn mismatched_types_causes_register_diff() {
588        let mut map = VarMap::new();
589
590        map.map_expr(ExprID(1), ExprID(1));
591        map.map_expr(ExprID(2), ExprID(2));
592        map.map_expr(ExprID(3), ExprID(3));
593        map.map_expr(ExprID(4), ExprID(4));
594
595        let lhs = statement!(reg e(0); Type::int(6); clock(e(2)); reset(e(3), e(4)); e(1));
596        let rhs = statement!(reg e(5); Type::int(5); clock(e(2)); reset(e(3), e(4)); e(1));
597
598        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
599
600        assert!(!compare_statements(&lhs, &rhs, &mut map));
601    }
602
603    // Constants
604
605    #[test]
606    fn identical_constants_match() {
607        let mut map = VarMap::new();
608
609        let lhs = statement!(const 0; Type::int(5); ConstantValue::int(10));
610        let rhs = statement!(const 0; Type::int(5); ConstantValue::int(10));
611
612        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
613
614        assert!(compare_statements(&lhs, &rhs, &mut map));
615    }
616
617    #[test]
618    fn identical_constants_update_expressions() {
619        let mut map = VarMap::new();
620
621        let lhs = statement!(const 0; Type::int(5); ConstantValue::int(10));
622        let rhs = statement!(const 1; Type::int(5); ConstantValue::int(10));
623
624        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
625
626        assert!(compare_statements(&lhs, &rhs, &mut map));
627
628        assert!(map.compare_exprs(ExprID(0), ExprID(1)));
629    }
630
631    #[test]
632    fn constant_type_mismatch_diff() {
633        let mut map = VarMap::new();
634
635        let lhs = statement!(const 0; Type::int(6); ConstantValue::int(10));
636        let rhs = statement!(const 0; Type::int(5); ConstantValue::int(10));
637
638        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
639
640        assert!(!compare_statements(&lhs, &rhs, &mut map));
641    }
642
643    #[test]
644    fn constant_value_mismatch_diff() {
645        let mut map = VarMap::new();
646
647        let lhs = statement!(const 0; Type::int(5); ConstantValue::int(11));
648        let rhs = statement!(const 0; Type::int(5); ConstantValue::int(10));
649
650        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
651
652        assert!(!compare_statements(&lhs, &rhs, &mut map));
653    }
654
655    #[test]
656    fn constant_value_type_mismatch_diff() {
657        let mut map = VarMap::new();
658
659        let lhs = statement!(const 0; Type::int(5); ConstantValue::Bool(false));
660        let rhs = statement!(const 0; Type::int(5); ConstantValue::int(10));
661
662        populate_var_map(&vec![lhs.clone()], &vec![rhs.clone()], &mut map).unwrap();
663
664        assert!(!compare_statements(&lhs, &rhs, &mut map));
665    }
666}
667
668#[cfg(test)]
669mod entity_comparison_tests {
670    use super::*;
671
672    use crate as spade_mir;
673    use crate::{entity, Type};
674
675    #[test]
676    fn identical_entities_have_no_diff() {
677        let mut var_map = VarMap::new();
678        var_map.map_name(1, 1);
679        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
680        } => n(1, "value"));
681        let rhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
682        } => n(1, "value"));
683
684        assert!(compare_entity(&lhs, &rhs, &mut var_map));
685    }
686
687    #[test]
688    fn names_are_mapped_for_inputs() {
689        let mut var_map = VarMap::new();
690        var_map.map_name(1, 1);
691
692        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
693        } => n(1, "value"));
694        let rhs = entity!("pong"; ("_i_clk", n(2, "clk"), Type::Bool) -> Type::int(6); {
695        } => n(1, "value"));
696
697        assert!(compare_entity(&lhs, &rhs, &mut var_map));
698
699        assert!(var_map.compare_name((&0, "clk"), (&2, "clk")));
700    }
701
702    #[test]
703    fn mismatched_name_causes_diff() {
704        let mut var_map = VarMap::new();
705        var_map.map_name(1, 1);
706
707        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
708        } => n(1, "value"));
709        let rhs = entity!("not_pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
710        } => n(1, "value"));
711
712        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
713    }
714
715    #[test]
716    fn input_types_must_match() {
717        let mut var_map = VarMap::new();
718        var_map.map_name(1, 1);
719
720        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
721        } => n(1, "value"));
722        let rhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::int(6)) -> Type::int(6); {
723        } => n(1, "value"));
724
725        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
726    }
727
728    #[test]
729    fn input_name_mismatch() {
730        let mut var_map = VarMap::new();
731        var_map.map_name(1, 1);
732
733        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
734        } => n(1, "value"));
735        let rhs = entity!("pong"; ("_i_not_clk", n(0, "clk"), Type::int(6)) -> Type::int(6); {
736        } => n(1, "value"));
737
738        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
739    }
740
741    #[test]
742    fn input_value_name_mismatch() {
743        let mut var_map = VarMap::new();
744        var_map.map_name(1, 1);
745
746        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
747        } => n(1, "value"));
748        let rhs = entity!("pong"; ("_i_clk", n(0, "not_clk"), Type::int(6)) -> Type::int(6); {
749        } => n(1, "value"));
750
751        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
752    }
753
754    #[test]
755    fn output_type_mismatch_causes_diff() {
756        let mut var_map = VarMap::new();
757        var_map.map_name(1, 1);
758
759        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(7); {
760        } => n(1, "value"));
761        let rhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
762        } => n(1, "value"));
763
764        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
765    }
766
767    #[test]
768    fn output_name_mismatches_are_caught() {
769        let mut var_map = VarMap::new();
770        var_map.map_name(1, 1);
771
772        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
773        } => e(1));
774        let rhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
775        } => e(2));
776
777        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
778    }
779
780    #[test]
781    fn mismatched_statements_cause_diff() {
782        let mut var_map = VarMap::new();
783        var_map.map_name(1, 1);
784
785        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
786            (e(0); Type::int(6); Add; n(1, "value"))
787        } => n(1, "value"));
788        let rhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
789            (e(0); Type::int(7); Add; n(1, "value"))
790        } => n(1, "value"));
791
792        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
793    }
794
795    #[test]
796    fn mismatched_statement_counts_diff() {
797        let mut var_map = VarMap::new();
798        var_map.map_name(1, 1);
799
800        let lhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
801            (e(0); Type::int(6); Add; n(1, "value"));
802            (e(0); Type::int(6); Add; n(1, "value"))
803        } => n(1, "value"));
804        let rhs = entity!("pong"; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
805            (e(0); Type::int(6); Add; n(1, "value"))
806        } => n(1, "value"));
807
808        assert!(!compare_entity(&lhs, &rhs, &mut var_map));
809    }
810}