prjunnamed_netlist/
rewrite.rs

1use std::{
2    borrow::Cow,
3    cell::RefCell,
4    collections::{HashMap, HashSet},
5};
6
7use crate::{design::TopoSortItem, Cell, ControlNet, Design, MetaItemRef, Net, Trit, Value};
8
9pub enum RewriteResult<'a> {
10    None,
11    Cell(Cell),
12    CellMeta(Cell, MetaItemRef<'a>),
13    Value(Value),
14}
15
16impl From<Value> for RewriteResult<'_> {
17    fn from(value: Value) -> Self {
18        RewriteResult::Value(value)
19    }
20}
21
22impl From<Net> for RewriteResult<'_> {
23    fn from(net: Net) -> Self {
24        RewriteResult::Value(net.into())
25    }
26}
27
28impl From<ControlNet> for RewriteResult<'_> {
29    fn from(cnet: ControlNet) -> Self {
30        match cnet {
31            ControlNet::Pos(net) => RewriteResult::Value(net.into()),
32            ControlNet::Neg(net) => RewriteResult::Cell(Cell::Not(net.into())),
33        }
34    }
35}
36
37impl From<Cell> for RewriteResult<'_> {
38    fn from(cell: Cell) -> Self {
39        RewriteResult::Cell(cell)
40    }
41}
42
43pub enum RewriteNetSource<'a> {
44    Const(Trit),
45    Opaque,
46    Cell(Cow<'a, Cell>, MetaItemRef<'a>, usize),
47}
48
49pub trait RewriteRuleset {
50    fn rewrite<'a>(&self, cell: &Cell, meta: MetaItemRef<'a>, rewriter: &Rewriter<'a>) -> RewriteResult<'a>;
51}
52
53pub struct Rewriter<'a> {
54    design: &'a Design,
55    rules: &'a [&'a dyn RewriteRuleset],
56    processed: RefCell<HashSet<Net>>,
57    cache: RefCell<HashMap<Cell, Value>>,
58}
59
60impl<'a> Rewriter<'a> {
61    pub fn find_cell(&self, net: Net) -> RewriteNetSource<'a> {
62        if !self.processed.borrow().contains(&net) && !net.is_const() {
63            return RewriteNetSource::Opaque;
64        }
65        match self.design.find_new_cell(net) {
66            Ok((cell, meta, bit)) => RewriteNetSource::Cell(cell, meta, bit),
67            Err(trit) => RewriteNetSource::Const(trit),
68        }
69    }
70
71    fn process_cell(&self, cell: &Cell, meta: MetaItemRef<'a>) -> RewriteResult<'a> {
72        let mut replacement_cell = None;
73        let mut replacement_meta = None;
74        'outer: loop {
75            for &rule in self.rules {
76                let cur_cell = replacement_cell.as_ref().unwrap_or(cell);
77                let cur_meta = replacement_meta.unwrap_or(meta);
78                let _guard = self.design.use_metadata(cur_meta);
79                match rule.rewrite(cur_cell, cur_meta, self) {
80                    RewriteResult::None => (),
81                    RewriteResult::Cell(new_cell) => {
82                        replacement_cell = Some(new_cell);
83                        continue 'outer;
84                    }
85                    RewriteResult::CellMeta(new_cell, new_meta) => {
86                        replacement_cell = Some(new_cell);
87                        replacement_meta = Some(new_meta);
88                        // TODO: should store meta on rewriter or pass to rules or something?
89                        continue 'outer;
90                    }
91                    RewriteResult::Value(value) => {
92                        return RewriteResult::Value(value);
93                    }
94                }
95            }
96            break;
97        }
98        let cell = replacement_cell.as_ref().unwrap_or(cell);
99        if let Some(value) = self.cache.borrow().get(&cell) {
100            let meta = replacement_meta.unwrap_or(meta);
101            self.design.append_metadata_by_net(value[0], meta);
102            RewriteResult::Value(value.clone())
103        } else {
104            match (replacement_cell, replacement_meta) {
105                (None, _) => RewriteResult::None,
106                (Some(cell), None) => RewriteResult::Cell(cell),
107                (Some(cell), Some(meta)) => RewriteResult::CellMeta(cell, meta),
108            }
109        }
110    }
111
112    pub fn add_cell(&self, cell: Cell) -> Value {
113        self.add_cell_meta(cell, self.design.get_use_metadata())
114    }
115
116    pub fn add_cell_meta(&self, cell: Cell, meta: MetaItemRef<'_>) -> Value {
117        let (cell, meta) = match self.process_cell(&cell, meta) {
118            RewriteResult::None => (cell, meta),
119            RewriteResult::Cell(new_cell) => (new_cell, meta),
120            RewriteResult::CellMeta(new_cell, new_meta) => (new_cell, new_meta),
121            RewriteResult::Value(value) => return value,
122        };
123        let value = self.design.add_cell_with_metadata_ref(cell.clone(), meta);
124        for net in &value {
125            self.processed.borrow_mut().insert(net);
126        }
127        if !cell.has_effects(self.design) {
128            self.cache.borrow_mut().insert(cell, value.clone());
129        }
130        value
131    }
132
133    fn run(&mut self) {
134        let worklist = self.design.topo_sort();
135        for item in worklist {
136            match item {
137                TopoSortItem::Cell(cell_ref) => {
138                    let output = cell_ref.output();
139                    let mut cell = cell_ref.get().into_owned();
140                    cell.visit_mut(|net| *net = self.design.map_net_new(*net));
141                    match self.process_cell(&cell, cell_ref.metadata()) {
142                        RewriteResult::None => {
143                            if !cell.has_effects(self.design) {
144                                self.cache.borrow_mut().insert(cell, output.clone());
145                            }
146                            for net in output {
147                                self.processed.borrow_mut().insert(net);
148                            }
149                        }
150                        RewriteResult::Cell(new_cell) => {
151                            cell_ref.replace(new_cell.clone());
152                            if !new_cell.has_effects(self.design) {
153                                self.cache.borrow_mut().insert(new_cell, output.clone());
154                            }
155                            for net in output {
156                                self.processed.borrow_mut().insert(net);
157                            }
158                        }
159                        RewriteResult::CellMeta(new_cell, new_meta) => {
160                            cell_ref.replace(new_cell.clone());
161                            cell_ref.append_metadata(new_meta);
162                            if !new_cell.has_effects(self.design) {
163                                self.cache.borrow_mut().insert(new_cell, output.clone());
164                            }
165                            for net in output {
166                                self.processed.borrow_mut().insert(net);
167                            }
168                        }
169                        RewriteResult::Value(value) => {
170                            assert_eq!(value.len(), output.len());
171                            for (net, new_net) in output.iter().zip(value) {
172                                self.design.replace_net(net, new_net);
173                                self.processed.borrow_mut().insert(net);
174                            }
175                            cell_ref.unalive();
176                        }
177                    }
178                }
179                TopoSortItem::CellBit(cell, bit) => {
180                    let mut slice = cell.get().slice(bit..bit + 1).unwrap();
181                    slice.visit_mut(|net| *net = self.design.map_net_new(*net));
182                    let new_value = self.add_cell_meta(slice, cell.metadata());
183                    let net = cell.output()[bit];
184                    self.design.replace_net(net, new_value[0]);
185                    self.processed.borrow_mut().insert(net);
186                }
187            }
188        }
189    }
190}
191
192impl Design {
193    pub fn rewrite(&mut self, rules: &[&dyn RewriteRuleset]) {
194        assert!(!self.is_changed());
195        let mut rewriter = Rewriter {
196            design: self,
197            rules,
198            processed: RefCell::new(HashSet::new()),
199            cache: RefCell::new(HashMap::new()),
200        };
201        rewriter.run();
202        self.compact();
203    }
204}