diff --git a/src/buddies/src/bd/strmxor.cc b/src/buddies/src/bd/strmxor.cc index 94ff7da1d..a18fc36cd 100644 --- a/src/buddies/src/bd/strmxor.cc +++ b/src/buddies/src/bd/strmxor.cc @@ -572,14 +572,22 @@ BD_PUBLIC int strmxor (int argc, char *argv[]) if (! silent && ! no_summary) { if (result) { - tl::info << "No differences found"; + tl::info << tl::to_string (tr ("No differences found")); } else { const char *line_format = " %-10s %-12s %s"; - const char *sep = " -------------------------------------------------------"; - tl::info << "Result summary (layers without differences are not shown):" << tl::endl; - tl::info << tl::sprintf (line_format, "Layer", "Output", "Differences (shape count)") << tl::endl << sep; + std::string headline; + if (deep) { + headline = tl::sprintf (line_format, tl::to_string (tr ("Layer")), tl::to_string (tr ("Output")), tl::to_string (tr ("Differences (hierarchical shape count)"))); + } else { + headline = tl::sprintf (line_format, tl::to_string (tr ("Layer")), tl::to_string (tr ("Output")), tl::to_string (tr ("Differences (shape count)"))); + } + + const char *sep = " ----------------------------------------------------------------"; + + tl::info << tl::to_string (tr ("Result summary (layers without differences are not shown):")) << tl::endl; + tl::info << headline << tl::endl << sep; int ti = -1; for (std::map, ResultDescriptor>::const_iterator r = results.begin (); r != results.end (); ++r) { @@ -587,17 +595,17 @@ BD_PUBLIC int strmxor (int argc, char *argv[]) if (r->first.first != ti) { ti = r->first.first; if (tolerances[ti] > db::epsilon) { - tl::info << tl::endl << "Tolerance " << tl::micron_to_string (tolerances[ti]) << ":" << tl::endl; - tl::info << tl::sprintf (line_format, "Layer", "Output", "Differences (shape count)") << tl::endl << sep; + tl::info << tl::endl << tl::to_string (tr ("Tolerance ")) << tl::micron_to_string (tolerances[ti]) << ":" << tl::endl; + tl::info << headline << tl::endl << sep; } } std::string out ("-"); std::string value; if (r->second.layer_a < 0 && ! dont_summarize_missing_layers) { - value = "(no such layer in first layout)"; + value = tl::to_string (tr ("(no such layer in first layout)")); } else if (r->second.layer_b < 0 && ! dont_summarize_missing_layers) { - value = "(no such layer in second layout)"; + value = tl::to_string (tr ("(no such layer in second layout)")); } else if (! r->second.is_empty ()) { if (r->second.layer_output >= 0 && r->second.layout) { out = r->second.layout->get_properties (r->second.layer_output).to_string (); @@ -857,7 +865,7 @@ bool run_deep_xor (const XORData &xor_data) result.layer_output = result.layout->insert_layer (lp); xor_res.insert_into (xor_data.output_layout, xor_data.output_cell, result.layer_output); } else { - result.shape_count = xor_res.count (); + result.shape_count = xor_res.hier_count (); } ++tol_index; diff --git a/src/db/db/dbArray.h b/src/db/db/dbArray.h index a4f51760f..ec8d16ef6 100644 --- a/src/db/db/dbArray.h +++ b/src/db/db/dbArray.h @@ -1571,6 +1571,17 @@ struct array_iterator } } + /** + * @brief Gets a value indicating whether the iterator is a synthetic one + * + * "is_singular" is true, if the iterator was default-created or with a single + * transformation. + */ + bool is_singular () const + { + return mp_base == 0; + } + private: trans_type m_trans; basic_array_iterator *mp_base; diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index ac3a31116..aa26e0adb 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -273,7 +273,7 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter) return; } - CellMapKey key (iter->top_cell ()->cell_index (), false, std::set ()); + CellMapKey key (iter->top_cell ()->cell_index (), false, std::set (), false); m_cm_entry = m_cell_map.find (key); if (m_cm_entry == m_cell_map.end ()) { @@ -351,7 +351,6 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co if (! key.clip_region.empty ()) { cn += "$CLIP_VAR"; description += "CLIP"; - } if (key.inactive) { cn += "$DIS"; @@ -360,6 +359,13 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co } description += "DISABLED"; } + if (key.skip_shapes) { + cn += "$SKIP"; + if (! description.empty ()) { + description += "/"; + } + description += "SKIPPED"; + } new_cell = mp_target->add_cell (cn.c_str ()); @@ -383,11 +389,11 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co } HierarchyBuilder::new_inst_mode -HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) +HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all, bool skip_shapes) { if (all) { - CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set ()); + CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set (), skip_shapes); db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ())); // for new cells, create this instance @@ -402,7 +408,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn } // To see the cell once, use NI_single. If we did see the cell already, skip the whole instance array. - return (m_cells_seen.find (key) == m_cells_seen.end ()) ? NI_single : NI_skip; + return (! skip_shapes && m_cells_seen.find (key) == m_cells_seen.end ()) ? NI_single : NI_skip; } else { @@ -413,7 +419,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn } bool -HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all) +HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes) { if (all) { @@ -429,7 +435,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db: return false; } - CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst_cell), clip_variant.second); + CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst_cell), clip_variant.second, skip_shapes); db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst_cell)); // for a new cell, create this instance @@ -441,7 +447,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db: } } - return (m_cells_seen.find (key) == m_cells_seen.end ()); + return ! skip_shapes && m_cells_seen.find (key) == m_cells_seen.end (); } } diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index 31a125f44..2bc2793d1 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -249,16 +249,16 @@ public: struct CellMapKey { CellMapKey () - : original_cell (0), inactive (false) + : original_cell (0), inactive (false), skip_shapes (false) { } - CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set &_clip_region) - : original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region) + CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set &_clip_region, bool _skip_shapes) + : original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region), skip_shapes (_skip_shapes) { } bool operator== (const CellMapKey &other) const { - return original_cell == other.original_cell && inactive == other.inactive && clip_region == other.clip_region; + return original_cell == other.original_cell && inactive == other.inactive && clip_region == other.clip_region && skip_shapes == other.skip_shapes; } bool operator< (const CellMapKey &other) const @@ -266,12 +266,14 @@ public: if (original_cell != other.original_cell) { return original_cell < other.original_cell; } if (inactive != other.inactive) { return inactive < other.inactive; } if (clip_region != other.clip_region) { return clip_region < other.clip_region; } + if (skip_shapes != other.skip_shapes) { return skip_shapes < other.skip_shapes; } return false; } db::cell_index_type original_cell; bool inactive; std::set clip_region; + bool skip_shapes; }; @@ -294,8 +296,8 @@ public: virtual void end (const RecursiveShapeIterator *iter); virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box ®ion, const box_tree_type *complex_region); virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell); - virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all); - virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all); + virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes); + virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes); virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region); /** diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index c92cd4bc4..b3965f9ce 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -74,6 +74,8 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI m_layer = d.m_layer; mp_cell = d.mp_cell; m_current_layer = d.m_current_layer; + m_skip_shapes = d.m_skip_shapes; + m_skip_shapes_member = d.m_skip_shapes_member; m_shape = d.m_shape; m_trans = d.m_trans; m_global_trans = d.m_global_trans; @@ -85,6 +87,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI m_local_complex_region_stack = d.m_local_complex_region_stack; m_local_region_stack = d.m_local_region_stack; m_skip_shapes_stack = d.m_skip_shapes_stack; + m_skip_shapes_member_stack = d.m_skip_shapes_member_stack; m_needs_reinit = d.m_needs_reinit; m_inst_quad_id = d.m_inst_quad_id; m_inst_quad_id_stack = d.m_inst_quad_id_stack; @@ -469,6 +472,8 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const m_local_region_stack.push_back (m_global_trans.inverted () * m_region); m_skip_shapes_stack.clear (); m_skip_shapes_stack.push_back (false); + m_skip_shapes_member_stack.clear (); + m_skip_shapes_member_stack.push_back (false); m_local_complex_region_stack.clear (); if (mp_complex_region.get ()) { @@ -814,39 +819,6 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const bool RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const { - bool skip_shapes = false; - - if (m_for_merged_input && ! m_skip_shapes_stack.back () && (! m_has_layers || m_layers.size () == 1)) { - - // Try some optimization: if the instance we're looking at is entirely covered - // by a rectangle (other objects are too expensive to check), then we skip it - // - // We check 10 shapes max. - - box_type inst_bx; - if (m_inst->size () == 1) { - inst_bx = m_inst->bbox (m_box_convert); - } else { - inst_bx = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ()); - } - - unsigned int l = m_has_layers ? m_layers.front () : m_layer; - auto si = cell ()->shapes (l).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel); - size_t nmax = 10; - while (! si.at_end () && nmax-- > 0) { - if (inst_bx.inside (si->rectangle ())) { - skip_shapes = true; - break; - } - ++si; - } - - } - - if (skip_shapes && (! receiver || ! receiver->wants_all_cells ())) { - return false; - } - tl_assert (mp_layout); m_trans_stack.push_back (m_trans); @@ -874,7 +846,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const } m_local_region_stack.push_back (new_region); - m_skip_shapes_stack.push_back (m_skip_shapes_stack.back () || skip_shapes); + m_skip_shapes_stack.push_back (m_skip_shapes); + m_skip_shapes_member_stack.push_back (m_skip_shapes_member); if (! m_local_complex_region_stack.empty ()) { @@ -948,6 +921,8 @@ RecursiveShapeIterator::pop () const m_inst = m_inst_iterators.back (); m_inst_array = m_inst_array_iterators.back (); m_inst_quad_id = m_inst_quad_id_stack.back (); + m_skip_shapes = m_skip_shapes_stack.back (); + m_skip_shapes_member = m_skip_shapes_member_stack.back (); m_inst_iterators.pop_back (); m_inst_array_iterators.pop_back (); m_inst_quad_id_stack.pop_back (); @@ -958,6 +933,7 @@ RecursiveShapeIterator::pop () const m_cells.pop_back (); m_local_region_stack.pop_back (); m_skip_shapes_stack.pop_back (); + m_skip_shapes_member_stack.pop_back (); if (! m_local_complex_region_stack.empty ()) { m_local_complex_region_stack.pop_back (); } @@ -982,7 +958,7 @@ RecursiveShapeIterator::start_shapes () const void RecursiveShapeIterator::new_layer () const { - if (m_skip_shapes_stack.back () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) { + if (skip_shapes () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) { m_shape = shape_iterator (); } else if (! m_overlapping) { m_shape = cell ()->shapes (m_layer).begin_touching (m_local_region_stack.back (), m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel); @@ -1029,6 +1005,32 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const new_inst (receiver); } +bool +RecursiveShapeIterator::instance_is_covered (const box_type &inst_bx, unsigned int layer) const +{ + // Try some optimization: if the instance we're looking at is entirely covered + // by a rectangle (other objects are too expensive to check), then we skip it + // + // We check 10 shapes max. + + auto si = cell ()->shapes (layer).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel); + size_t nmax = 10; + while (! si.at_end () && nmax-- > 0) { + if (inst_bx.inside (si->rectangle ())) { + return true; + } + ++si; + } + + return false; +} + +bool +RecursiveShapeIterator::skip_shapes () const +{ + return m_skip_shapes_stack.back () || m_skip_shapes_member_stack.back (); +} + void RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const { @@ -1055,9 +1057,19 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const all_of_instance = m_local_complex_region_stack.empty (); } + m_skip_shapes = skip_shapes (); + m_skip_shapes_member = false; + + if (m_for_merged_input && ! m_skip_shapes && (! m_has_layers || m_layers.size () == 1)) { + box_type inst_bx = m_inst->bbox (m_box_convert); + m_skip_shapes = instance_is_covered (inst_bx, m_has_layers ? m_layers.front () : m_layer); + } + RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all; if (receiver) { - ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance); + ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance, m_skip_shapes); + } else if (m_skip_shapes) { + ni = RecursiveShapeReceiver::NI_skip; } if (ni == RecursiveShapeReceiver::NI_skip) { @@ -1095,7 +1107,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const // skip instance array members not part of the complex region while (! m_inst_array.at_end ()) { - db::Box ia_box = m_inst->complex_trans (*m_inst_array) * cell_bbox (m_inst->cell_index ()); + box_type ia_box = m_inst->complex_trans (*m_inst_array) * cell_bbox (m_inst->cell_index ()); if (! is_outside_complex_region (ia_box)) { break; } else { @@ -1105,12 +1117,31 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const } - while (! m_inst_array.at_end () && receiver) { - if (receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) { - break; - } else { - ++m_inst_array; + m_skip_shapes_member = false; + + while (! m_inst_array.at_end () && (m_for_merged_input || receiver)) { + + m_skip_shapes_member = m_skip_shapes; + if (m_for_merged_input && ! m_inst_array.is_singular () && ! m_skip_shapes && (! m_has_layers || m_layers.size () == 1)) { + + box_type ia_box = m_inst->complex_trans (*m_inst_array) * cell_bbox (m_inst->cell_index ()); + m_skip_shapes_member = instance_is_covered (ia_box, m_has_layers ? m_layers.front () : m_layer); + } + + bool skip = false; + if (receiver) { + skip = ! receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance (), m_skip_shapes_member); + } else { + skip = m_skip_shapes_member; + } + + if (skip) { + ++m_inst_array; + } else { + break; + } + } } diff --git a/src/db/db/dbRecursiveShapeIterator.h b/src/db/db/dbRecursiveShapeIterator.h index 26ee32b7e..b0e685686 100644 --- a/src/db/db/dbRecursiveShapeIterator.h +++ b/src/db/db/dbRecursiveShapeIterator.h @@ -868,6 +868,7 @@ private: mutable unsigned int m_layer; mutable const cell_type *mp_cell; mutable size_t m_current_layer; + mutable bool m_skip_shapes, m_skip_shapes_member; mutable shape_iterator m_shape; mutable cplx_trans_type m_trans; mutable std::vector m_trans_stack; @@ -876,7 +877,7 @@ private: mutable std::vector m_cells; mutable std::vector m_local_complex_region_stack; mutable std::vector m_local_region_stack; - mutable std::vector m_skip_shapes_stack; + mutable std::vector m_skip_shapes_stack, m_skip_shapes_member_stack; mutable bool m_needs_reinit; mutable size_t m_inst_quad_id; mutable std::vector m_inst_quad_id_stack; @@ -899,6 +900,8 @@ private: bool down (RecursiveShapeReceiver *receiver) const; void pop () const; + bool instance_is_covered (const box_type &inst_bx, unsigned int layer) const; + bool skip_shapes () const; bool is_outside_complex_region (const db::Box &box) const; void set_inactive (bool a) const @@ -1013,8 +1016,11 @@ public: * - NI_all: iterate all members through "new_inst_member" * - NI_single: iterate a single member (the first one) * - NI_skip: skips the whole array (not a single instance is iterated) + * + * The "skip_shapes" parameter indicates that the instance is visited with the + * purpose of skipping all shapes. This is used to implement the "for_merged" optimization. */ - virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; } + virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/, bool /*skip_shapes*/) { return NI_all; } /** * @brief Enters a new array member of the instance @@ -1026,8 +1032,11 @@ public: * "all" is true, if an instance array is iterated in "all" mode (see new_inst). * * If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered. + * + * The "skip_shapes" parameter indicates that the instance member is visited with the + * purpose of skipping all shapes. This is used to implement the "for_merged" optimization. */ - virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; } + virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/, bool /*skip_shapes*/) { return true; } /** * @brief Delivers a shape diff --git a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc index 7c386f011..c7205fbf3 100644 --- a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc @@ -756,15 +756,25 @@ namespace { : public db::RecursiveShapeReceiver { public: - FlatPusher (std::set *boxes) : mp_boxes (boxes) { } + FlatPusher (std::set *boxes = 0) : mp_boxes (boxes ? boxes : &m_boxes) { } void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { mp_boxes->insert (trans * shape.bbox ()); } + std::string to_string () const + { + std::vector s; + for (auto i = mp_boxes->begin (); i != mp_boxes->end (); ++i) { + s.push_back (i->to_string ()); + } + return tl::join (s.begin (), s.end (), ";"); + } + private: std::set *mp_boxes; + std::set m_boxes; }; } @@ -1038,7 +1048,7 @@ public: m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; } - virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) + virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all, bool /*skip_shapes*/) { m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ()); if (all) { @@ -1048,7 +1058,7 @@ public: return NI_all; } - virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) + virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all, bool /*skip_shapes*/) { m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (always_apply * trans); if (all) { @@ -1073,9 +1083,9 @@ class ReceiverRejectingACellInstanceArray public: ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { } - virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all) + virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes) { - LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all); + LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all, skip_shapes); return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip; } @@ -1089,9 +1099,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne public: ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { } - virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all) + virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes) { - LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all); + LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all, skip_shapes); return inst.object ().cell_index () != m_rejected ? NI_all : NI_single; } @@ -1105,9 +1115,9 @@ class ReceiverRejectingACellInstance public: ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { } - virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all) + virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all, bool skip_shapes) { - LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all); + LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all, skip_shapes); return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected; } @@ -1586,49 +1596,174 @@ TEST(12_ForMerged) db::RecursiveShapeIterator i1 (*g, c0, 0); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); i1.set_for_merged_input (true); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); std::vector lv; lv.push_back (0); i1 = db::RecursiveShapeIterator (*g, c0, lv); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); i1.set_for_merged_input (true); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); lv.push_back (1); // empty, but kills "for merged" optimization i1 = db::RecursiveShapeIterator (*g, c0, lv); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000);(100,0;1100,1100);(1200,0;2200,1100);(0,100;1000,1200)"); + } i1.set_for_merged_input (true); x = collect(i1, *g); // no longer optimized EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000);(100,0;1100,1100);(1200,0;2200,1100);(0,100;1000,1200)"); + } i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-100, 0, 100, 50)); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)"); + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000);(100,0;1100,1100)"); + } + i1.set_for_merged_input (true); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000)"); + } i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-101, 0, 100, 50)); i1.set_overlapping (true); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000)"); + } i1.set_for_merged_input (true); x = collect(i1, *g); EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(-1200,0;-100,1000);(0,0;3000,2000)"); + } } +TEST(12b_ForMerged) +{ + std::unique_ptr g (new db::Layout ()); + g->insert_layer (0); + g->insert_layer (1); + db::Cell &c0 (g->cell (g->add_cell ())); + db::Cell &c1 (g->cell (g->add_cell ())); + + db::Box b (0, 100, 1000, 1200); + c0.shapes (0).insert (db::Box (0, 0, 3000, 2200)); + c1.shapes (0).insert (b); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (2000, 1000)), db::Vector (0, 2000), db::Vector (2000, 0), 2l, 2l)); + + std::string x; + + db::RecursiveShapeIterator i1 (*g, c0, 0); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](0,100;1000,1200)/[$2](2000,1100;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(0,100;1000,1200);(2000,1100;3000,2200);(4000,1100;5000,2200);(2000,3100;3000,4200);(4000,3100;5000,4200)"); + } + + i1.set_for_merged_input (true); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + { + FlatPusher f; + i1.reset (); + i1.push (&f); + EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(4000,1100;5000,2200);(2000,3100;3000,4200);(4000,3100;5000,4200)"); + } + + i1.set_for_merged_input (false); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](0,100;1000,1200)/[$2](2000,1100;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)"); + EXPECT_EQ (collect_with_copy(i1, *g), x); + + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 2000)))); + + db::RecursiveShapeIterator i2 (*g, c0, 0); + + x = collect(i2, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](0,100;1000,1200)/[$2](2000,1100;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)/[$2](0,2100;1000,3200)"); + EXPECT_EQ (collect_with_copy(i2, *g), x); + + { + FlatPusher f; + i2.reset (); + i2.push (&f); + EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(0,100;1000,1200);(2000,1100;3000,2200);(4000,1100;5000,2200);(0,2100;1000,3200);(2000,3100;3000,4200);(4000,3100;5000,4200)"); + } + + i2.set_for_merged_input (true); + x = collect(i2, *g); + EXPECT_EQ (x, "[$1](0,0;3000,2200)/[$2](2000,3100;3000,4200)/[$2](4000,1100;5000,2200)/[$2](4000,3100;5000,4200)/[$2](0,2100;1000,3200)"); + EXPECT_EQ (collect_with_copy(i2, *g), x); + + { + FlatPusher f; + i2.reset (); + i2.push (&f); + EXPECT_EQ (f.to_string (), "(0,0;3000,2200);(4000,1100;5000,2200);(0,2100;1000,3200);(2000,3100;3000,4200);(4000,3100;5000,4200)"); + } +} TEST(13_ForMergedPerformance) { diff --git a/src/rdb/rdb/rdbUtils.cc b/src/rdb/rdb/rdbUtils.cc index 6d0181162..4692b35bd 100644 --- a/src/rdb/rdb/rdbUtils.cc +++ b/src/rdb/rdb/rdbUtils.cc @@ -146,7 +146,7 @@ public: m_cell_stack.pop_back (); } - virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) + virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/, bool /*skip_shapes*/) { db::cell_index_type ci = inst.object ().cell_index (); if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) {