calyx_ir/
guard.rs

1use crate::Printer;
2
3use super::{Builder, Cell, NumAttr, Port, RRC};
4use calyx_utils::Error;
5use itertools::Itertools;
6use std::collections::HashSet;
7use std::fmt::{Debug, Display};
8use std::mem;
9use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
10use std::{cmp::Ordering, hash::Hash, rc::Rc};
11
12#[derive(Debug, Clone, Default, Eq, PartialEq)]
13#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
14pub struct Nothing;
15
16impl Display for Nothing {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        write!(f, "")
19    }
20}
21
22/// Comparison operations that can be performed between ports by [Guard::CompOp].
23#[derive(Debug, Clone, PartialEq, Eq)]
24#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
25pub enum PortComp {
26    /// p1 == p2
27    Eq,
28    /// p1 != p2
29    Neq,
30    /// p1 > p2
31    Gt,
32    /// p1 < p2
33    Lt,
34    /// p1 >= p2
35    Geq,
36    /// p1 <= p2
37    Leq,
38}
39
40/// An assignment guard which has pointers to the various ports from which it reads.
41#[derive(Debug, Clone, Default)]
42#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
43pub enum Guard<T> {
44    /// Represents `c1 || c2`.
45    Or(Box<Guard<T>>, Box<Guard<T>>),
46    /// Represents `c1 && c2`.
47    And(Box<Guard<T>>, Box<Guard<T>>),
48    /// Represents `!c1`
49    Not(Box<Guard<T>>),
50    #[default]
51    /// The constant true
52    True,
53    /// Comparison operator.
54    CompOp(PortComp, RRC<Port>, RRC<Port>),
55    /// Uses the value on a port as the condition. Same as `p1 == true`
56    Port(RRC<Port>),
57    /// Other types of information.
58    Info(T),
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
62#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
63pub struct StaticTiming {
64    interval: (u64, u64),
65}
66
67impl Display for StaticTiming {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        if self.interval.0 + 1 == self.interval.1 {
70            write!(f, "%{}", self.interval.0)
71        } else {
72            write!(f, "%[{}:{}]", self.interval.0, self.interval.1)
73        }
74    }
75}
76
77impl StaticTiming {
78    /// creates a new `StaticTiming` struct
79    pub fn new(interval: (u64, u64)) -> Self {
80        StaticTiming { interval }
81    }
82
83    /// returns the (u64, u64) interval for `struct`
84    pub fn get_interval(&self) -> (u64, u64) {
85        self.interval
86    }
87
88    /// overwrites the current `interval` to be `new_interval`
89    pub fn set_interval(&mut self, new_interval: (u64, u64)) {
90        self.interval = new_interval;
91    }
92}
93
94impl<T> Hash for Guard<T>
95where
96    T: ToString,
97{
98    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
99        match self {
100            Guard::Or(l, r) | Guard::And(l, r) => {
101                l.hash(state);
102                r.hash(state)
103            }
104            Guard::CompOp(_, l, r) => {
105                l.borrow().name.hash(state);
106                l.borrow().get_parent_name().hash(state);
107                r.borrow().name.hash(state);
108                r.borrow().get_parent_name().hash(state);
109            }
110            Guard::Not(inner) => inner.hash(state),
111            Guard::Port(p) => {
112                p.borrow().name.hash(state);
113                p.borrow().get_parent_name().hash(state);
114            }
115            Guard::True => {}
116            Guard::Info(i) => i.to_string().hash(state),
117        }
118    }
119}
120
121impl From<Guard<Nothing>> for Guard<StaticTiming> {
122    /// Turns a normal guard into a static guard
123    fn from(g: Guard<Nothing>) -> Self {
124        match g {
125            Guard::Or(left, right) => {
126                let l = Self::from(*left);
127                let r = Self::from(*right);
128                Guard::Or(Box::new(l), Box::new(r))
129            }
130            Guard::And(left, right) => {
131                let l = Self::from(*left);
132                let r = Self::from(*right);
133                Guard::And(Box::new(l), Box::new(r))
134            }
135            Guard::Not(c) => {
136                let inside = Self::from(*c);
137                Guard::Not(Box::new(inside))
138            }
139            Guard::True => Guard::True,
140            Guard::CompOp(pc, left, right) => Guard::CompOp(pc, left, right),
141            Guard::Port(p) => Guard::Port(p),
142            Guard::Info(_) => {
143                unreachable!(
144                    "{:?}: Guard<Nothing> should not be of the
145                info variant type",
146                    g
147                )
148            }
149        }
150    }
151}
152
153impl<T> Guard<T> {
154    /// Returns true definitely `Guard::True`.
155    /// Returning false does not mean that the guard is not true.
156    pub fn is_true(&self) -> bool {
157        match self {
158            Guard::True => true,
159            Guard::Port(p) => p.borrow().is_constant(1, 1),
160            _ => false,
161        }
162    }
163
164    /// Checks if the guard is always false.
165    /// Returning false does not mean that the guard is not false.
166    pub fn is_false(&self) -> bool {
167        match self {
168            Guard::Not(g) => g.is_true(),
169            _ => false,
170        }
171    }
172
173    /// returns true if the self is !cell_name, false otherwise.
174    pub fn is_not_done(&self, cell_name: &crate::Id) -> bool {
175        if let Guard::Not(g) = self {
176            if let Guard::Port(port) = &(**g) {
177                return port.borrow().attributes.has(NumAttr::Done)
178                    && port.borrow().get_parent_name() == cell_name;
179            }
180        }
181        false
182    }
183
184    /// Update the guard in place. Replaces this guard with `upd(self)`.
185    /// Uses `std::mem::take` for the in-place update.
186    #[inline(always)]
187    pub fn update<F>(&mut self, upd: F)
188    where
189        F: FnOnce(Guard<T>) -> Guard<T>,
190    {
191        let old = mem::take(self);
192        let new = upd(old);
193        *self = new;
194    }
195
196    /// Return the string corresponding to the guard operation.
197    pub fn op_str(&self) -> String {
198        match self {
199            Guard::And(..) => "&".to_string(),
200            Guard::Or(..) => "|".to_string(),
201            Guard::CompOp(op, _, _) => match op {
202                PortComp::Eq => "==".to_string(),
203                PortComp::Neq => "!=".to_string(),
204                PortComp::Gt => ">".to_string(),
205                PortComp::Lt => "<".to_string(),
206                PortComp::Geq => ">=".to_string(),
207                PortComp::Leq => "<=".to_string(),
208            },
209            Guard::Not(..) => "!".to_string(),
210            Guard::Port(..) | Guard::True | Guard::Info(_) => {
211                panic!("No operator string for Guard::Port/True/Info")
212            }
213        }
214    }
215
216    pub fn port(p: RRC<Port>) -> Self {
217        if p.borrow().is_constant(1, 1) {
218            Guard::True
219        } else {
220            Guard::Port(p)
221        }
222    }
223
224    pub fn and(self, rhs: Guard<T>) -> Self
225    where
226        T: Eq,
227    {
228        if rhs == Guard::True {
229            self
230        } else if self == Guard::True {
231            rhs
232        } else if self == rhs {
233            self
234        } else {
235            Guard::And(Box::new(self), Box::new(rhs))
236        }
237    }
238
239    pub fn or(self, rhs: Guard<T>) -> Self
240    where
241        T: Eq,
242    {
243        match (self, rhs) {
244            (Guard::True, _) | (_, Guard::True) => Guard::True,
245            (Guard::Not(n), g) | (g, Guard::Not(n)) => {
246                if *n == Guard::True {
247                    g
248                } else {
249                    Guard::Or(Box::new(Guard::Not(n)), Box::new(g))
250                }
251            }
252            (l, r) => {
253                if l == r {
254                    l
255                } else {
256                    Guard::Or(Box::new(l), Box::new(r))
257                }
258            }
259        }
260    }
261
262    pub fn eq(self, other: Guard<T>) -> Self
263    where
264        T: Debug + Eq + ToString,
265    {
266        match (self, other) {
267            (Guard::Port(l), Guard::Port(r)) => {
268                Guard::CompOp(PortComp::Eq, l, r)
269            }
270            (l, r) => {
271                unreachable!(
272                    "Cannot build Guard::Eq using `{}' and `{}'",
273                    Printer::guard_str(&l),
274                    Printer::guard_str(&r),
275                )
276            }
277        }
278    }
279
280    pub fn neq(self, other: Guard<T>) -> Self
281    where
282        T: Debug + Eq + ToString,
283    {
284        match (self, other) {
285            (Guard::Port(l), Guard::Port(r)) => {
286                Guard::CompOp(PortComp::Neq, l, r)
287            }
288            (l, r) => {
289                unreachable!(
290                    "Cannot build Guard::Eq using `{}' and `{}'",
291                    Printer::guard_str(&l),
292                    Printer::guard_str(&r),
293                )
294            }
295        }
296    }
297
298    pub fn le(self, other: Guard<T>) -> Self
299    where
300        T: Debug + Eq + ToString,
301    {
302        match (self, other) {
303            (Guard::Port(l), Guard::Port(r)) => {
304                Guard::CompOp(PortComp::Leq, l, r)
305            }
306            (l, r) => {
307                unreachable!(
308                    "Cannot build Guard::Eq using `{}' and `{}'",
309                    Printer::guard_str(&l),
310                    Printer::guard_str(&r),
311                )
312            }
313        }
314    }
315
316    pub fn lt(self, other: Guard<T>) -> Self
317    where
318        T: Debug + Eq + ToString,
319    {
320        match (self, other) {
321            (Guard::Port(l), Guard::Port(r)) => {
322                Guard::CompOp(PortComp::Lt, l, r)
323            }
324            (l, r) => {
325                unreachable!(
326                    "Cannot build Guard::Eq using `{}' and `{}'",
327                    Printer::guard_str(&l),
328                    Printer::guard_str(&r),
329                )
330            }
331        }
332    }
333
334    pub fn ge(self, other: Guard<T>) -> Self
335    where
336        T: Debug + Eq + ToString,
337    {
338        match (self, other) {
339            (Guard::Port(l), Guard::Port(r)) => {
340                Guard::CompOp(PortComp::Geq, l, r)
341            }
342            (l, r) => {
343                unreachable!(
344                    "Cannot build Guard::Eq using `{}' and `{}'",
345                    Printer::guard_str(&l),
346                    Printer::guard_str(&r),
347                )
348            }
349        }
350    }
351
352    pub fn gt(self, other: Guard<T>) -> Self
353    where
354        T: Debug + Eq + ToString,
355    {
356        match (self, other) {
357            (Guard::Port(l), Guard::Port(r)) => {
358                Guard::CompOp(PortComp::Gt, l, r)
359            }
360            (l, r) => {
361                unreachable!(
362                    "Cannot build Guard::Eq using `{}' and `{}'",
363                    Printer::guard_str(&l),
364                    Printer::guard_str(&r),
365                )
366            }
367        }
368    }
369
370    /// Returns all the ports used by this guard.
371    pub fn all_ports(&self) -> Vec<RRC<Port>> {
372        match self {
373            Guard::Port(a) => vec![Rc::clone(a)],
374            Guard::And(l, r) | Guard::Or(l, r) => {
375                let mut atoms = l.all_ports();
376                atoms.append(&mut r.all_ports());
377                atoms
378            }
379            Guard::CompOp(_, l, r) => {
380                vec![Rc::clone(l), Rc::clone(r)]
381            }
382            Guard::Not(g) => g.all_ports(),
383            Guard::True => vec![],
384            Guard::Info(_) => vec![],
385        }
386    }
387}
388
389/// Helper functions for the guard.
390impl<T> Guard<T> {
391    /// Mutates a guard by calling `f` on every leaf in the
392    /// guard tree and replacing the leaf with the guard that `f`
393    /// returns.
394    pub fn for_each<F>(&mut self, f: &mut F)
395    where
396        F: FnMut(RRC<Port>) -> Option<Guard<T>>,
397    {
398        match self {
399            Guard::And(l, r) | Guard::Or(l, r) => {
400                l.for_each(f);
401                r.for_each(f);
402            }
403            Guard::Not(inner) => {
404                inner.for_each(f);
405            }
406            Guard::CompOp(_, l, r) => {
407                match f(Rc::clone(l)) {
408                    Some(Guard::Port(p)) => *l = p,
409                    Some(_) => unreachable!(
410                        "Cannot replace port inside comparison operator"
411                    ),
412                    None => {}
413                }
414                match f(Rc::clone(r)) {
415                    Some(Guard::Port(p)) => *r = p,
416                    Some(_) => unreachable!(
417                        "Cannot replace port inside comparison operator"
418                    ),
419                    None => {}
420                }
421            }
422            Guard::Port(port) => {
423                let guard = f(Rc::clone(port))
424                    .unwrap_or_else(|| Guard::port(Rc::clone(port)));
425                *self = guard;
426            }
427            Guard::True => {}
428            Guard::Info(_) =>
429                // Info shouldn't count as port
430                {}
431        }
432    }
433
434    /// runs f(info) on each Guard::Info in `guard`.
435    /// if `f(info)` = Some(result)` replaces interval with result.
436    /// if `f(info)` = None` does nothing.
437    pub fn for_each_info<F>(&mut self, f: &mut F)
438    where
439        F: FnMut(&mut T) -> Option<Guard<T>>,
440    {
441        match self {
442            Guard::And(l, r) | Guard::Or(l, r) => {
443                l.for_each_info(f);
444                r.for_each_info(f);
445            }
446            Guard::Not(inner) => {
447                inner.for_each_info(f);
448            }
449            Guard::True | Guard::Port(_) | Guard::CompOp(_, _, _) => {}
450            Guard::Info(timing_interval) => {
451                if let Some(new_interval) = f(timing_interval) {
452                    *self = new_interval
453                }
454            }
455        }
456    }
457
458    /// runs f(info) on each info in `guard`.
459    /// f should return Result<(), Error>, meaning that it essentially does
460    /// nothing if the `f` returns OK(()), but returns an appropraite error otherwise
461    pub fn check_for_each_info<F>(&self, f: &mut F) -> Result<(), Error>
462    where
463        F: Fn(&T) -> Result<(), Error>,
464    {
465        match self {
466            Guard::And(l, r) | Guard::Or(l, r) => {
467                let l_result = l.check_for_each_info(f);
468                if l_result.is_err() {
469                    l_result
470                } else {
471                    r.check_for_each_info(f)
472                }
473            }
474            Guard::Not(inner) => inner.check_for_each_info(f),
475            Guard::True | Guard::Port(_) | Guard::CompOp(_, _, _) => Ok(()),
476            Guard::Info(timing_interval) => f(timing_interval),
477        }
478    }
479}
480
481impl Guard<StaticTiming> {
482    /// updates self -> self & interval
483    pub fn add_interval(&mut self, timing_interval: StaticTiming) {
484        self.update(|g| g.and(Guard::Info(timing_interval)));
485    }
486
487    /// Take a static assignment guard and the latency of the group in which the assignment
488    /// exists, and provide a list of states, relative to the group's latency, in which
489    /// the static assignment should be valid.
490    pub fn compute_live_states(&self, group_latency: u64) -> HashSet<u64> {
491        match self {
492            Self::True => (0..group_latency).collect(),
493            Self::And(l, r) => l
494                .compute_live_states(group_latency)
495                .intersection(&r.compute_live_states(group_latency))
496                .cloned()
497                .collect(),
498            Self::Or(l, r) => l
499                .compute_live_states(group_latency)
500                .union(&r.compute_live_states(group_latency))
501                .cloned()
502                .collect(),
503            Self::Not(g) => {
504                let dont_include = g.compute_live_states(group_latency);
505                (0..group_latency)
506                    .filter(|state| dont_include.contains(state))
507                    .collect()
508            }
509            Self::Info(static_timing) => {
510                let (b, e) = static_timing.interval;
511                (b..e).collect()
512            }
513            Self::CompOp(..) | Self::Port(_) => {
514                HashSet::from_iter(0..group_latency)
515            }
516        }
517    }
518
519    /// Replace every interval `[a1, a_n]` in a static timing guard with
520    /// `counter.out == a_1 | counter.out == a_2 | ... | counter.out == a_{n-1}`
521    pub fn replace_static_timing(
522        &mut self,
523        builder: &mut Builder,
524        counter: &RRC<Cell>,
525        width: &u64,
526        domain: &u64,
527    ) {
528        match self {
529            Self::True | Self::CompOp(..) | Self::Port(..) => (),
530            Self::Not(g) => {
531                g.replace_static_timing(builder, counter, width, domain)
532            }
533            Self::And(l, r) | Self::Or(l, r) => {
534                l.replace_static_timing(builder, counter, width, domain);
535                r.replace_static_timing(builder, counter, width, domain);
536            }
537            Self::Info(static_timing) => {
538                let (b, e) = static_timing.get_interval();
539                let interval = (b..e).collect_vec();
540                let complement = (0..b).chain(e..*domain).collect_vec();
541                self.update(|_| {
542                    if interval.len() < complement.len() {
543                        match interval.into_iter().fold(None, |acc, state| {
544                            let state_const =
545                                builder.add_constant(state, *width);
546                            let state_guard = Self::CompOp(
547                                PortComp::Eq,
548                                counter.borrow().get("out"),
549                                state_const.borrow().get("out"),
550                            );
551                            match acc {
552                                None => Some(state_guard),
553                                Some(existing_guard) => {
554                                    Some(existing_guard.or(state_guard))
555                                }
556                            }
557                        }) {
558                            Some(g) => g,
559                            None => {
560                                let zero = builder.add_constant(0, 1);
561                                let out_port = zero.borrow().get("out");
562                                Self::port(out_port)
563                            }
564                        }
565                    } else {
566                        match complement.into_iter().fold(None, |acc, state| {
567                            let state_const =
568                                builder.add_constant(state, *width);
569                            let state_guard = Self::CompOp(
570                                PortComp::Neq,
571                                counter.borrow().get("out"),
572                                state_const.borrow().get("out"),
573                            );
574                            match acc {
575                                None => Some(state_guard),
576                                Some(existing_guard) => {
577                                    Some(existing_guard.and(state_guard))
578                                }
579                            }
580                        }) {
581                            Some(g) => g,
582                            None => Self::True,
583                        }
584                    }
585                });
586            }
587        }
588    }
589
590    /// Take a static assignment guard and get rid of all static timing portions
591    /// of the guard. This is useful when we know the cycles `c` at which the assignment
592    /// will be active, and we can separately construct the assignment guard
593    /// like `dst = c ? src` instead of `dst = beg <= c <= end ? src`.
594    pub fn remove_static_timing_info(&mut self) {
595        match self {
596            Self::Port(_) | Self::CompOp(..) | Self::True => (),
597            Self::Info(_) => {
598                self.update(|_| Self::True);
599            }
600            Self::Not(g) => match g.as_mut() {
601                Self::Info(_) => self.update(|_| Self::True),
602                _ => g.remove_static_timing_info(),
603            },
604            Self::And(l, r) => match (l.as_mut(), r.as_mut()) {
605                (Self::Info(_), Self::Info(_)) => self.update(|_| Self::True),
606                (Self::Info(_), _) => {
607                    r.remove_static_timing_info();
608                    l.update(|_| Self::True);
609                }
610                (_, Self::Info(_)) => {
611                    l.remove_static_timing_info();
612                    r.update(|_| Self::True);
613                }
614                _ => {
615                    l.remove_static_timing_info();
616                    r.remove_static_timing_info();
617                }
618            },
619            Self::Or(l, r) => match (l.as_mut(), r.as_mut()) {
620                (Self::Info(_), Self::Info(_)) => self.update(|_| Self::True),
621                (Self::Info(_), _) => {
622                    r.remove_static_timing_info();
623                    l.update(|_| Self::not(Self::True))
624                }
625                (_, Self::Info(_)) => {
626                    l.remove_static_timing_info();
627                    r.update(|_| Self::not(Self::True))
628                }
629                _ => {
630                    l.remove_static_timing_info();
631                    r.remove_static_timing_info();
632                }
633            },
634        }
635    }
636}
637
638impl From<Guard<StaticTiming>> for Guard<Nothing> {
639    fn from(guard: Guard<StaticTiming>) -> Guard<Nothing> {
640        match guard {
641            Guard::True => Guard::True,
642            Guard::Port(p) => Guard::Port(p),
643            Guard::CompOp(cmp, p1, p2) => Guard::CompOp(cmp, p1, p2),
644
645            Guard::And(l, r) => {
646                let l_new = Guard::from(*l);
647                let r_new = Guard::from(*r);
648                Guard::And(Box::new(l_new), Box::new(r_new))
649            }
650            Guard::Or(l, r) => {
651                let l_new = Guard::from(*l);
652                let r_new = Guard::from(*r);
653                Guard::Or(Box::new(l_new), Box::new(r_new))
654            }
655            Guard::Not(g) => {
656                let g_new = Guard::from(*g);
657                Guard::Not(Box::new(g_new))
658            }
659            Guard::Info(_) => {
660                unreachable!("Guard should not contain any `info` nodes;")
661            }
662        }
663    }
664}
665
666/// Construct guards from ports
667impl<T> From<RRC<Port>> for Guard<T> {
668    fn from(port: RRC<Port>) -> Self {
669        Guard::Port(Rc::clone(&port))
670    }
671}
672
673impl<T> PartialEq for Guard<T>
674where
675    T: Eq,
676{
677    fn eq(&self, other: &Self) -> bool {
678        match (self, other) {
679            (Guard::Or(la, ra), Guard::Or(lb, rb))
680            | (Guard::And(la, ra), Guard::And(lb, rb)) => la == lb && ra == rb,
681            (Guard::CompOp(opa, la, ra), Guard::CompOp(opb, lb, rb)) => {
682                (opa == opb)
683                    && (la.borrow().get_parent_name(), &la.borrow().name)
684                        == (lb.borrow().get_parent_name(), &lb.borrow().name)
685                    && (ra.borrow().get_parent_name(), &ra.borrow().name)
686                        == (rb.borrow().get_parent_name(), &rb.borrow().name)
687            }
688            (Guard::Not(a), Guard::Not(b)) => a == b,
689            (Guard::Port(a), Guard::Port(b)) => {
690                (a.borrow().get_parent_name(), &a.borrow().name)
691                    == (b.borrow().get_parent_name(), &b.borrow().name)
692            }
693            (Guard::True, Guard::True) => true,
694            (Guard::Info(i1), Guard::Info(i2)) => i1 == i2,
695            _ => false,
696        }
697    }
698}
699
700impl<T> Eq for Guard<T> where T: Eq {}
701
702/// Define order on guards
703impl<T> PartialOrd for Guard<T>
704where
705    T: Eq,
706{
707    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
708        Some(self.cmp(other))
709    }
710}
711
712/// Define an ordering on the precedence of guards. Guards are
713/// considered equal when they have the same precedence.
714impl<T> Ord for Guard<T>
715where
716    T: Eq,
717{
718    fn cmp(&self, other: &Self) -> Ordering {
719        match (self, other) {
720            (Guard::Or(..), Guard::Or(..))
721            | (Guard::And(..), Guard::And(..))
722            | (Guard::CompOp(..), Guard::CompOp(..))
723            | (Guard::Not(..), Guard::Not(..))
724            | (Guard::Port(..), Guard::Port(..))
725            | (Guard::Info(_), Guard::Info(_))
726            | (Guard::True, Guard::True) => Ordering::Equal,
727            (Guard::Or(..), _) => Ordering::Greater,
728            (_, Guard::Or(..)) => Ordering::Less,
729            (Guard::And(..), _) => Ordering::Greater,
730            (_, Guard::And(..)) => Ordering::Less,
731            (Guard::CompOp(PortComp::Leq, ..), _) => Ordering::Greater,
732            (_, Guard::CompOp(PortComp::Leq, ..)) => Ordering::Less,
733            (Guard::CompOp(PortComp::Geq, ..), _) => Ordering::Greater,
734            (_, Guard::CompOp(PortComp::Geq, ..)) => Ordering::Less,
735            (Guard::CompOp(PortComp::Lt, ..), _) => Ordering::Greater,
736            (_, Guard::CompOp(PortComp::Lt, ..)) => Ordering::Less,
737            (Guard::CompOp(PortComp::Gt, ..), _) => Ordering::Greater,
738            (_, Guard::CompOp(PortComp::Gt, ..)) => Ordering::Less,
739            (Guard::CompOp(PortComp::Eq, ..), _) => Ordering::Greater,
740            (_, Guard::CompOp(PortComp::Eq, ..)) => Ordering::Less,
741            (Guard::CompOp(PortComp::Neq, ..), _) => Ordering::Greater,
742            (_, Guard::CompOp(PortComp::Neq, ..)) => Ordering::Less,
743            (Guard::Not(..), _) => Ordering::Greater,
744            (_, Guard::Not(..)) => Ordering::Less,
745            (Guard::Port(..), _) => Ordering::Greater,
746            (_, Guard::Port(..)) => Ordering::Less,
747            // maybe we should change this?
748            (Guard::Info(..), _) => Ordering::Greater,
749            (_, Guard::Info(..)) => Ordering::Less,
750        }
751    }
752}
753
754/////////////// Sugar for convience constructors /////////////
755
756/// Construct a Guard::And:
757/// ```
758/// let and_guard = g1 & g2;
759/// ```
760impl<T> BitAnd for Guard<T>
761where
762    T: Eq,
763{
764    type Output = Self;
765
766    fn bitand(self, other: Self) -> Self::Output {
767        self.and(other)
768    }
769}
770
771/// Construct a Guard::Or:
772/// ```
773/// let or_guard = g1 | g2;
774/// ```
775impl<T> BitOr for Guard<T>
776where
777    T: Eq,
778{
779    type Output = Self;
780
781    fn bitor(self, other: Self) -> Self::Output {
782        self.or(other)
783    }
784}
785
786/// Construct a Guard::Or:
787/// ```
788/// let not_guard = !g1;
789/// ```
790impl<T> Not for Guard<T> {
791    type Output = Self;
792
793    fn not(self) -> Self {
794        match self {
795            Guard::CompOp(PortComp::Eq, lhs, rhs) => {
796                Guard::CompOp(PortComp::Neq, lhs, rhs)
797            }
798            Guard::CompOp(PortComp::Neq, lhs, rhs) => {
799                Guard::CompOp(PortComp::Eq, lhs, rhs)
800            }
801            Guard::CompOp(PortComp::Gt, lhs, rhs) => {
802                Guard::CompOp(PortComp::Leq, lhs, rhs)
803            }
804            Guard::CompOp(PortComp::Lt, lhs, rhs) => {
805                Guard::CompOp(PortComp::Geq, lhs, rhs)
806            }
807            Guard::CompOp(PortComp::Geq, lhs, rhs) => {
808                Guard::CompOp(PortComp::Lt, lhs, rhs)
809            }
810            Guard::CompOp(PortComp::Leq, lhs, rhs) => {
811                Guard::CompOp(PortComp::Gt, lhs, rhs)
812            }
813            Guard::Not(expr) => *expr,
814            _ => Guard::Not(Box::new(self)),
815        }
816    }
817}
818
819/// Update a Guard with Or.
820/// ```
821/// g1 |= g2;
822/// ```
823impl<T> BitOrAssign for Guard<T>
824where
825    T: Eq,
826{
827    fn bitor_assign(&mut self, other: Self) {
828        self.update(|old| old | other)
829    }
830}
831
832/// Update a Guard with Or.
833/// ```
834/// g1 &= g2;
835/// ```
836impl<T> BitAndAssign for Guard<T>
837where
838    T: Eq,
839{
840    fn bitand_assign(&mut self, other: Self) {
841        self.update(|old| old & other)
842    }
843}