1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
use crate::ir::{
    self,
    traversal::{Action, Named, VisResult, Visitor},
    CloneName, LibrarySignatures,
};
use std::collections::HashSet;

/// Removes unused groups and combinational groups from components.
/// A group is considered in use when it shows up in an [ir::Enable].
/// A combinational group is considered in use when it is a part of an
/// [ir::If] or [ir::While] or [ir::Invoke].
#[derive(Default)]
pub struct DeadGroupRemoval {
    used_groups: HashSet<ir::Id>,
    used_comb_groups: HashSet<ir::Id>,
}

impl Named for DeadGroupRemoval {
    fn name() -> &'static str {
        "dead-group-removal"
    }

    fn description() -> &'static str {
        "removes unsed groups from components"
    }
}

impl Visitor for DeadGroupRemoval {
    fn enable(
        &mut self,
        s: &mut ir::Enable,
        _comp: &mut ir::Component,
        _sigs: &ir::LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        self.used_groups.insert(s.group.borrow().clone_name());
        Ok(Action::Continue)
    }

    fn finish_if(
        &mut self,
        s: &mut ir::If,
        _comp: &mut ir::Component,
        _sigs: &ir::LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        if let Some(cg) = &s.cond {
            self.used_comb_groups.insert(cg.borrow().clone_name());
        }
        Ok(Action::Continue)
    }

    fn invoke(
        &mut self,
        s: &mut ir::Invoke,
        _comp: &mut ir::Component,
        _sigs: &ir::LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        if let Some(cg) = &s.comb_group {
            self.used_comb_groups.insert(cg.borrow().clone_name());
        }
        Ok(Action::Continue)
    }

    fn finish_while(
        &mut self,
        s: &mut ir::While,
        _comp: &mut ir::Component,
        _sigs: &ir::LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        if let Some(cg) = &s.cond {
            self.used_comb_groups.insert(cg.borrow().clone_name());
        }
        Ok(Action::Continue)
    }

    fn finish(
        &mut self,
        comp: &mut ir::Component,
        _sigs: &LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        // Groups that are driven by their `go` signals should not be
        // removed.
        for group in comp.groups.iter() {
            for assign in &group.borrow().assignments {
                let dst = assign.dst.borrow();
                if dst.is_hole() && dst.name == "go" {
                    self.used_groups.insert(dst.get_parent_name().clone());
                }
            }
        }

        // Remove Groups that are not used
        comp.groups
            .retain(|g| self.used_groups.contains(g.borrow().name()));
        comp.comb_groups
            .retain(|cg| self.used_comb_groups.contains(cg.borrow().name()));

        Ok(Action::Stop)
    }
}