scir/
merge.rs

1//! Merge SCIR libraries.
2
3use uniquify::Names;
4
5use super::*;
6
7/// Keeps track of cell and primitive IDs after a library is merged.
8pub struct MergedMapping {
9    cells: HashMap<CellId, CellId>,
10    primitives: HashMap<PrimitiveId, PrimitiveId>,
11}
12
13struct Merger<'a, S: Schema + ?Sized> {
14    /// Source cell ID -> destination cell ID
15    cell_mapping: HashMap<CellId, CellId>,
16    /// Source primitive ID -> destination primitive ID
17    primitive_mapping: HashMap<PrimitiveId, PrimitiveId>,
18    /// Destination cell ID -> name.
19    names: Names<CellId>,
20    dst: &'a mut LibraryBuilder<S>,
21    src: LibraryBuilder<S>,
22    /// The list of source cell IDs to merge into `dst`.
23    ///
24    /// If [`None`], all source cells will be merged.
25    merge_cells: Option<Vec<CellId>>,
26}
27
28impl<'a, S: Schema + ?Sized> Merger<'a, S> {
29    #[inline]
30    fn new(dst: &'a mut LibraryBuilder<S>, src: LibraryBuilder<S>) -> Self {
31        Self {
32            cell_mapping: HashMap::with_capacity(src.cells.len()),
33            primitive_mapping: HashMap::with_capacity(src.primitives.len()),
34            names: Names::with_capacity(src.cells.len() + dst.cells.len()),
35            dst,
36            src,
37            merge_cells: None,
38        }
39    }
40
41    #[inline]
42    fn merge_cells(
43        dst: &'a mut LibraryBuilder<S>,
44        src: LibraryBuilder<S>,
45        cells: impl IntoIterator<Item = CellId>,
46    ) -> Self {
47        Self {
48            cell_mapping: HashMap::with_capacity(src.cells.len()),
49            primitive_mapping: HashMap::with_capacity(src.primitives.len()),
50            names: Names::with_capacity(src.cells.len() + dst.cells.len()),
51            dst,
52            src,
53            merge_cells: Some(cells.into_iter().collect()),
54        }
55    }
56
57    fn merge(mut self) -> MergedMapping {
58        for (id, cell) in self.dst.cells() {
59            self.names.reserve_name(id, cell.name());
60        }
61        let mut cells: Vec<_> = if let Some(cells) = self.merge_cells.as_ref() {
62            self.src
63                .cells_used_by(cells.iter().copied())
64                .iter()
65                .map(|&id| (id, self.src.cell(id).clone()))
66                .collect()
67        } else {
68            self.src.cells.drain(..).collect()
69        };
70        let primitives: Vec<_> = self.src.primitives.drain(..).collect();
71        for (id, cell) in cells.iter_mut() {
72            self.assign_cell_identifiers(*id, cell);
73        }
74        for (id, _) in primitives.iter() {
75            self.assign_primitive_identifiers(*id);
76        }
77        for (id, cell) in cells {
78            self.merge_cell(id, cell);
79        }
80        for (id, primitive) in primitives {
81            self.merge_primitive(id, primitive);
82        }
83
84        MergedMapping {
85            cells: self.cell_mapping,
86            primitives: self.primitive_mapping,
87        }
88    }
89
90    fn assign_cell_identifiers(&mut self, id: CellId, cell: &mut Cell) {
91        let n_id = self.dst.alloc_cell_id();
92        let n_name = self.names.assign_name(n_id, &cell.name);
93        self.cell_mapping.insert(id, n_id);
94        cell.name = n_name;
95    }
96
97    fn assign_primitive_identifiers(&mut self, id: PrimitiveId) {
98        let n_id = self.dst.alloc_primitive_id();
99        self.primitive_mapping.insert(id, n_id);
100    }
101
102    fn merge_cell(&mut self, id: CellId, mut cell: Cell) {
103        for (_, inst) in cell.instances.iter_mut() {
104            match inst.child() {
105                ChildId::Cell(c) => {
106                    inst.child = (*self.cell_mapping.get(&c).unwrap()).into();
107                }
108                ChildId::Primitive(p) => {
109                    inst.child = (*self.primitive_mapping.get(&p).unwrap()).into();
110                }
111            }
112        }
113        let n_id = self.cell_mapping.get(&id).unwrap();
114        self.dst.add_cell_with_id(*n_id, cell);
115    }
116
117    fn merge_primitive(&mut self, id: PrimitiveId, primitive: S::Primitive) {
118        let n_id = self.primitive_mapping.get(&id).unwrap();
119        self.dst.add_primitive_with_id(*n_id, primitive);
120    }
121}
122
123impl MergedMapping {
124    /// Get the cell ID in the merged library
125    /// corresponding to `old_cell_id` in the original library.
126    ///
127    /// # Panics
128    ///
129    /// Panics if `old_cell_id` is not a valid cell ID
130    /// in the original library.
131    pub fn new_cell_id(&self, old_cell_id: CellId) -> CellId {
132        self.cells.get(&old_cell_id).copied().unwrap()
133    }
134    /// Get the primitive ID in the merged library
135    /// corresponding to `old_primitive_id` in the original library.
136    ///
137    /// # Panics
138    ///
139    /// Panics if `old_primitive_id` is not a valid primitive ID
140    /// in the original library.
141    pub fn new_primitive_id(&self, old_primitive_id: PrimitiveId) -> PrimitiveId {
142        self.primitives.get(&old_primitive_id).copied().unwrap()
143    }
144}
145
146impl<S: Schema + ?Sized> LibraryBuilder<S> {
147    /// Merges another SCIR library into the current library.
148    pub fn merge(&mut self, other: Self) -> MergedMapping {
149        Merger::new(self, other).merge()
150    }
151
152    /// Merges the given cells from another SCIR library into the current library.
153    pub fn merge_cells(
154        &mut self,
155        other: Self,
156        cells: impl IntoIterator<Item = CellId>,
157    ) -> MergedMapping {
158        Merger::merge_cells(self, other, cells).merge()
159    }
160}