diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc index 486e84688..08da24b28 100644 --- a/src/db/db/dbColdProxy.cc +++ b/src/db/db/dbColdProxy.cc @@ -60,14 +60,36 @@ ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOr } i->second->push_back (this); } + + layout.register_cold_proxy (this); } ColdProxy::~ColdProxy () { + if (layout ()) { + layout ()->unregister_cold_proxy (this); + } + delete mp_context_info; mp_context_info = 0; } +void +ColdProxy::unregister () +{ + if (layout ()) { + layout ()->unregister_cold_proxy (this); + } +} + +void +ColdProxy::reregister () +{ + if (layout ()) { + layout ()->register_cold_proxy (this); + } +} + Cell * ColdProxy::clone (Layout &layout) const { diff --git a/src/db/db/dbColdProxy.h b/src/db/db/dbColdProxy.h index 69fb84511..8d6d2fcd3 100644 --- a/src/db/db/dbColdProxy.h +++ b/src/db/db/dbColdProxy.h @@ -81,6 +81,16 @@ public: return true; } + /** + * @brief Reimplemented from Cell: unregisters the proxy at the layout + */ + virtual void unregister (); + + /** + * @brief Reimplemented from Cell: reregisters the proxy at the layout + */ + virtual void reregister (); + /** * @brief Gets a list of cold proxies for a given library name */ diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 9411dcef3..977aa82f7 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -337,6 +337,37 @@ private: // ----------------------------------------------------------------- // Implementation of the ProxyContextInfo class +bool +LayoutOrCellContextInfo::operator== (const LayoutOrCellContextInfo &other) const +{ + return lib_name == other.lib_name && + cell_name == other.cell_name && + pcell_name == other.pcell_name && + pcell_parameters == other.pcell_parameters && + meta_info == other.meta_info; +} + +bool +LayoutOrCellContextInfo::operator< (const LayoutOrCellContextInfo &other) const +{ + if (lib_name != other.lib_name) { + return lib_name < other.lib_name; + } + if (cell_name != other.cell_name) { + return cell_name < other.cell_name; + } + if (pcell_name != other.pcell_name) { + return pcell_name < other.pcell_name; + } + if (pcell_parameters != other.pcell_parameters) { + return pcell_parameters < other.pcell_parameters; + } + if (meta_info != other.meta_info) { + return meta_info < other.meta_info; + } + return false; +} + LayoutOrCellContextInfo LayoutOrCellContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) { @@ -540,6 +571,7 @@ Layout::clear () m_pcell_ids.clear (); m_lib_proxy_map.clear (); + m_cold_proxy_map.clear (); m_meta_info.clear (); } @@ -568,6 +600,7 @@ Layout::operator= (const Layout &d) } m_lib_proxy_map = d.m_lib_proxy_map; + m_cold_proxy_map = d.m_cold_proxy_map; m_cell_ptrs.resize (d.m_cell_ptrs.size (), 0); @@ -809,6 +842,7 @@ Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat db::mem_stat (stat, purpose, cat, m_pcells, true, (void *) this); db::mem_stat (stat, purpose, cat, m_pcell_ids, true, (void *) this); db::mem_stat (stat, purpose, cat, m_lib_proxy_map, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_cold_proxy_map, true, (void *) this); db::mem_stat (stat, purpose, cat, m_meta_info, true, (void *) this); db::mem_stat (stat, purpose, cat, m_shape_repository, true, (void *) this); db::mem_stat (stat, purpose, cat, m_array_repository, true, (void *) this); @@ -1505,6 +1539,11 @@ Layout::register_cell_name (const char *name, cell_index_type ci) void Layout::rename_cell (cell_index_type id, const char *name) { + static const char *anonymous_name = ""; + if (! name) { + name = anonymous_name; + } + tl_assert (id < m_cell_names.size ()); if (strcmp (m_cell_names [id], name) != 0) { @@ -1521,7 +1560,10 @@ Layout::rename_cell (cell_index_type id, const char *name) delete [] m_cell_names [id]; m_cell_names [id] = cp; - m_cell_map.insert (std::make_pair (cp, id)); + // NOTE: anonymous cells (empty name string) are not registered in the cell name map + if (*cp != 0) { + m_cell_map.insert (std::make_pair (cp, id)); + } // to enforce a redraw and a rebuild cell_name_changed (); @@ -1690,27 +1732,119 @@ Layout::cleanup (const std::set &keep) return; } + if (tl::verbosity () >= 30) { + tl::info << "Cleaning up layout .."; + } + + // Do some polishing of the proxies - sometimes, specifically when resolving indirect library references, + // different proxies to the same library object exist. We can identify them and clean them up, so there + // is a single reference. We can also try to ensure that cell names reflect the library cell names. + // The latter is good for LVS for example. + + { + db::LayoutLocker locker (this); + + // join library proxies pointing to the same object + + for (auto c = m_lib_proxy_map.begin (); c != m_lib_proxy_map.end (); ) { + + auto c0 = c++; + size_t n = 1; + while (c != m_lib_proxy_map.end () && c->first == c0->first) { + ++n; + ++c; + } + + if (n > 1) { + auto cc = c0; + ++cc; + while (cc != c) { + if (keep.find (cc->second) == keep.end ()) { + if (tl::verbosity () >= 30) { + tl::info << "Joining lib proxy " << cell_name (cc->second) << " into " << cell_name (c0->second); + } + replace_instances_of (cc->second, c0->second); + } + ++cc; + } + } + + } + + // join cold proxies pointing to the same object + + for (auto c = m_cold_proxy_map.begin (); c != m_cold_proxy_map.end (); ) { + + auto c0 = c++; + size_t n = 1; + while (c != m_cold_proxy_map.end () && c->first == c0->first) { + ++n; + ++c; + } + + if (n > 1) { + auto cc = c0; + ++cc; + while (cc != c) { + if (keep.find (cc->second) == keep.end ()) { + if (tl::verbosity () >= 30) { + tl::info << "Joining cold proxy " << cell_name (cc->second) << " into " << cell_name (c0->second); + } + replace_instances_of (cc->second, c0->second); + } + ++cc; + } + } + + } + + } + + std::set cells_to_delete; + // deleting cells may create new top cells which need to be deleted as well, hence we iterate // until there are no more cells to delete while (true) { // delete all cells that are top cells and are proxies. Those cells are proxies no longer required. - std::set cells_to_delete; for (top_down_iterator c = begin_top_down (); c != end_top_cells (); ++c) { - if (cell (*c).is_proxy ()) { + if (cell (*c).is_proxy () && keep.find (*c) == keep.end ()) { cells_to_delete.insert (*c); } } - for (std::set::const_iterator k = keep.begin (); k != keep.end (); ++k) { - cells_to_delete.erase (*k); - } - if (cells_to_delete.empty ()) { break; } delete_cells (cells_to_delete); + cells_to_delete.clear (); + + } + + // Try to ensure that cell names reflect the library cell names. The latter is good for LVS for example. + + for (auto c = m_lib_proxy_map.begin (); c != m_lib_proxy_map.end (); ++c) { + + std::string bn = cell (c->second).get_basic_name (); + if (bn != cell_name (c->second) && ! cell_by_name (bn.c_str ()).first) { + if (tl::verbosity () >= 30) { + tl::info << "Renaming lib proxy " << cell_name (c->second) << " to " << bn; + } + rename_cell (c->second, bn.c_str ()); + } + + } + + for (auto c = m_cold_proxy_map.begin (); c != m_cold_proxy_map.end (); ++c) { + + std::string bn = cell (c->second).get_basic_name (); + if (bn != cell_name (c->second) && ! cell_by_name (bn.c_str ()).first) { + if (tl::verbosity () >= 30) { + tl::info << "Renaming cold proxy " << cell_name (c->second) << " to " << bn; + } + rename_cell (c->second, bn.c_str ()); + } } } @@ -3151,13 +3285,32 @@ Layout::variant_name (cell_index_type cell_index) const void Layout::register_lib_proxy (db::LibraryProxy *lib_proxy) { - m_lib_proxy_map.insert (std::make_pair (std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ()), lib_proxy->Cell::cell_index ())); + auto key = std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ()); + + auto l = m_lib_proxy_map.find (key); + while (l != m_lib_proxy_map.end () && l->first == key) { + if (l->second == lib_proxy->Cell::cell_index ()) { + return; + } + ++l; + } + + m_lib_proxy_map.insert (std::make_pair (key, lib_proxy->Cell::cell_index ())); } void Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy) { - m_lib_proxy_map.erase (std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ())); + auto key = std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ()); + + auto l = m_lib_proxy_map.find (key); + while (l != m_lib_proxy_map.end () && l->first == key) { + if (l->second == lib_proxy->Cell::cell_index ()) { + m_lib_proxy_map.erase (l); + break; + } + ++l; + } } void @@ -3177,9 +3330,13 @@ Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_t cell_index_type Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) { - lib_proxy_map::const_iterator lp = m_lib_proxy_map.find (std::make_pair (lib->get_id (), cell_index)); - if (lp != m_lib_proxy_map.end ()) { + auto key = std::make_pair (lib->get_id (), cell_index); + + lib_proxy_map::const_iterator lp = m_lib_proxy_map.find (key); + if (lp != m_lib_proxy_map.end () && lp->first == key) { + return lp->second; + } else { // create a new unique name @@ -3210,35 +3367,82 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) } } +void +Layout::register_cold_proxy (db::ColdProxy *cold_proxy) +{ + auto l = m_cold_proxy_map.find (cold_proxy->context_info ()); + while (l != m_cold_proxy_map.end () && l->first == cold_proxy->context_info ()) { + if (l->second == cold_proxy->Cell::cell_index ()) { + return; + } + ++l; + } + + m_cold_proxy_map.insert (std::make_pair (cold_proxy->context_info (), cold_proxy->Cell::cell_index ())); +} + +void +Layout::unregister_cold_proxy (db::ColdProxy *cold_proxy) +{ + auto l = m_cold_proxy_map.find (cold_proxy->context_info ()); + while (l != m_cold_proxy_map.end () && l->first == cold_proxy->context_info ()) { + if (l->second == cold_proxy->Cell::cell_index ()) { + m_cold_proxy_map.erase (l); + break; + } + ++l; + } +} + +std::pair +Layout::find_cold_proxy (const db::LayoutOrCellContextInfo &info) +{ + cold_proxy_map::const_iterator lp = m_cold_proxy_map.find (info); + if (lp != m_cold_proxy_map.end () && lp->first == info) { + return std::make_pair (true, lp->second); + } else { + return std::make_pair (false, 0); + } +} + cell_index_type Layout::create_cold_proxy (const db::LayoutOrCellContextInfo &info) { - // create a new unique name - std::string b; - if (! info.cell_name.empty ()) { - b = info.cell_name; - } else if (! info.pcell_name.empty ()) { - b = info.pcell_name; + cold_proxy_map::const_iterator lp = m_cold_proxy_map.find (info); + if (lp != m_cold_proxy_map.end () && lp->first == info) { + + return lp->second; + + } else { + + // create a new unique name + std::string b; + if (! info.cell_name.empty ()) { + b = info.cell_name; + } else if (! info.pcell_name.empty ()) { + b = info.pcell_name; + } + if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { + b = uniquify_cell_name (b.c_str ()); + } + + // create a new cell (a LibraryProxy) + cell_index_type new_index = allocate_new_cell (); + + ColdProxy *proxy = new ColdProxy (new_index, *this, info); + m_cells.push_back_ptr (proxy); + m_cell_ptrs [new_index] = proxy; + + // enter its index and cell_name + register_cell_name (b.c_str (), new_index); + + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); + } + + return new_index; + } - if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { - b = uniquify_cell_name (b.c_str ()); - } - - // create a new cell (a LibraryProxy) - cell_index_type new_index = allocate_new_cell (); - - ColdProxy *proxy = new ColdProxy (new_index, *this, info); - m_cells.push_back_ptr (proxy); - m_cell_ptrs [new_index] = proxy; - - // enter its index and cell_name - register_cell_name (b.c_str (), new_index); - - if (manager () && manager ()->transacting ()) { - manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); - } - - return new_index; } void diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index e68b5746c..b9bc0f1c9 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -62,6 +62,7 @@ class PCellDeclaration; class PCellHeader; class Library; class LibraryProxy; +class ColdProxy; class CellMapping; class LayerMapping; class Region; @@ -427,6 +428,9 @@ struct DB_PUBLIC LayoutOrCellContextInfo std::map pcell_parameters; std::map > meta_info; + bool operator== (const LayoutOrCellContextInfo &other) const; + bool operator< (const LayoutOrCellContextInfo &other) const; + static LayoutOrCellContextInfo deserialize (std::vector::const_iterator from, std::vector::const_iterator to); void serialize (std::vector &strings); @@ -469,7 +473,8 @@ public: typedef db::pcell_id_type pcell_id_type; typedef std::map pcell_name_map; typedef pcell_name_map::const_iterator pcell_iterator; - typedef std::map, cell_index_type> lib_proxy_map; + typedef std::multimap, cell_index_type> lib_proxy_map; + typedef std::multimap cold_proxy_map; typedef LayerIterator layer_iterator; typedef size_t meta_info_name_id_type; typedef std::map meta_info_map; @@ -1003,6 +1008,12 @@ public: */ void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false); + /** + * @brief Find an existing cold proxy for a given context + * @return A pair of success flag and cell index of the proxy + */ + std::pair find_cold_proxy (const db::LayoutOrCellContextInfo &info); + /** * @brief Creates a cold proxy representing the given context information */ @@ -1839,6 +1850,20 @@ public: */ void unregister_lib_proxy (db::LibraryProxy *lib_proxy); + /** + * @brief Register a cold proxy + * + * This method is used by ColdProxy to register itself. + */ + void register_cold_proxy (db::ColdProxy *cold_proxy); + + /** + * @brief Unregister a cold proxy + * + * This method is used by ColdProxy to unregister itself. + */ + void unregister_cold_proxy (db::ColdProxy *cold_proxy); + /** * @brief Gets the editable status of this layout * @@ -2153,6 +2178,7 @@ private: std::vector m_pcells; pcell_name_map m_pcell_ids; lib_proxy_map m_lib_proxy_map; + cold_proxy_map m_cold_proxy_map; bool m_do_cleanup; bool m_editable; std::map m_meta_info_name_map; diff --git a/src/db/db/dbLibraryProxy.cc b/src/db/db/dbLibraryProxy.cc index cd93e048c..ce299c888 100644 --- a/src/db/db/dbLibraryProxy.cc +++ b/src/db/db/dbLibraryProxy.cc @@ -221,14 +221,25 @@ LibraryProxy::update (db::ImportLayerMapping *layer_mapping) real_lib = db::LibraryManager::instance ().lib (lp->lib_id ()); } - inst.object ().cell_index (layout ()->get_lib_proxy (real_lib, real_cil)); - ColdProxy *cp = dynamic_cast (&real_lib->layout ().cell (real_cil)); if (cp) { + // The final item is a cold proxy ("" cell) - treat it like // a library proxy as it may become one in the future, but replace it // by a cold proxy now. - layout ()->create_cold_proxy_as (cp->context_info (), inst.object ().cell_index ()); + + auto p = layout ()->find_cold_proxy (cp->context_info ()); + if (p.first) { + // reuse existing proxy + inst.object ().cell_index (p.second); + } else { + // create a new proxy, reusing the first library proxy's replica + inst.object ().cell_index (layout ()->get_lib_proxy (real_lib, real_cil)); + layout ()->create_cold_proxy_as (cp->context_info (), inst.object ().cell_index ()); + } + + } else { + inst.object ().cell_index (layout ()->get_lib_proxy (real_lib, real_cil)); } inst.transform_into (db::ICplxTrans (lib->layout ().dbu () / layout ()->dbu ())); diff --git a/src/db/db/dbLibraryProxy.h b/src/db/db/dbLibraryProxy.h index 233348daa..1e18d206b 100644 --- a/src/db/db/dbLibraryProxy.h +++ b/src/db/db/dbLibraryProxy.h @@ -129,12 +129,12 @@ public: /** * @brief Reimplemented from Cell: unregisters the proxy at the layout */ - void unregister (); + virtual void unregister (); /** * @brief Reimplemented from Cell: reregisters the proxy at the layout */ - void reregister (); + virtual void reregister (); private: lib_id_type m_lib_id; diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index d39e025ae..65ca6e4f9 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -773,8 +773,8 @@ TEST(7_monsterlib) } // as NOEX and NOEX2 are not present, a number of references are defunct (aka cold proxies) - EXPECT_EQ (num_defunct (layout), size_t (15)); - EXPECT_EQ (num_cells (layout), size_t (46)); + EXPECT_EQ (num_defunct (layout), size_t (6)); + EXPECT_EQ (num_cells (layout), size_t (25)); EXPECT_EQ (num_top_cells (layout), size_t (1)); // NOTE: normalization would spoil the layout, so don't do it @@ -794,7 +794,7 @@ TEST(7_monsterlib) // all references now need to be resolved EXPECT_EQ (num_defunct (layout), size_t (0)); - EXPECT_EQ (num_cells (layout), size_t (36)); + EXPECT_EQ (num_cells (layout), size_t (25)); EXPECT_EQ (num_top_cells (layout), size_t (1)); db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/libman/design_au2.gds", db::NormalizationMode (db::NoNormalization | db::WithoutCellNames | db::AsPolygons)); @@ -807,7 +807,7 @@ TEST(7_monsterlib) // all references now need to be resolved EXPECT_EQ (num_defunct (layout), size_t (0)); - EXPECT_EQ (num_cells (layout), size_t (32)); + EXPECT_EQ (num_cells (layout), size_t (25)); EXPECT_EQ (num_top_cells (layout), size_t (1)); db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/libman/design_au3.gds", db::NormalizationMode (db::NoNormalization | db::WithoutCellNames | db::AsPolygons)); @@ -816,8 +816,8 @@ TEST(7_monsterlib) db::LibraryManager::instance ().delete_lib (lib_noex2); // after removing the libraries, we have defunct cells again - EXPECT_EQ (num_defunct (layout), size_t (11)); - EXPECT_EQ (num_cells (layout), size_t (32)); + EXPECT_EQ (num_defunct (layout), size_t (6)); + EXPECT_EQ (num_cells (layout), size_t (25)); EXPECT_EQ (num_top_cells (layout), size_t (1)); // but the layout did not change @@ -827,8 +827,8 @@ TEST(7_monsterlib) db::LibraryManager::instance ().delete_lib (lib_ex2); // after removing all libraries, we have even more defunct cells (i.e. all, except top) - EXPECT_EQ (num_defunct (layout), size_t (19)); - EXPECT_EQ (num_cells (layout), size_t (32)); + EXPECT_EQ (num_defunct (layout), size_t (12)); + EXPECT_EQ (num_cells (layout), size_t (25)); EXPECT_EQ (num_top_cells (layout), size_t (1)); // but the layout did not change diff --git a/testdata/libman/design_au1.gds b/testdata/libman/design_au1.gds index 5419c7754..9d9d354d8 100644 Binary files a/testdata/libman/design_au1.gds and b/testdata/libman/design_au1.gds differ diff --git a/testdata/libman/design_au2.gds b/testdata/libman/design_au2.gds index d7153f8f4..cc5f9d1e3 100644 Binary files a/testdata/libman/design_au2.gds and b/testdata/libman/design_au2.gds differ diff --git a/testdata/libman/design_au3.gds b/testdata/libman/design_au3.gds index a3b7482aa..cc5f9d1e3 100644 Binary files a/testdata/libman/design_au3.gds and b/testdata/libman/design_au3.gds differ diff --git a/testdata/libman/design_au4.gds b/testdata/libman/design_au4.gds index 803e4325c..cc5f9d1e3 100644 Binary files a/testdata/libman/design_au4.gds and b/testdata/libman/design_au4.gds differ diff --git a/testdata/libman/design_au5.gds b/testdata/libman/design_au5.gds index 892d011db..cc5f9d1e3 100644 Binary files a/testdata/libman/design_au5.gds and b/testdata/libman/design_au5.gds differ