Maybe fixing basic issues with strmxor

1. Output of shape countsi in deep mode was hierarchical with
   output file, flat without
2. Refactoring of XOR (for_merged optimization) needed to
   create cover cell variants
This commit is contained in:
Matthias Koefferlein 2025-04-07 00:53:43 +02:00
parent 449a9a968e
commit 41e9cb5893
8 changed files with 280 additions and 78 deletions

View File

@ -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<std::pair<int, db::LayerProperties>, 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;

View File

@ -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 <Coord> *mp_base;

View File

@ -273,7 +273,7 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
return;
}
CellMapKey key (iter->top_cell ()->cell_index (), false, std::set<db::Box> ());
CellMapKey key (iter->top_cell ()->cell_index (), false, std::set<db::Box> (), 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<db::Box> ());
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set<db::Box> (), 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 &region, 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 &region, 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 ();
}
}

View File

@ -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<db::Box> &_clip_region)
: original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region)
CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set<db::Box> &_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<db::Box> 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, 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 &region, const box_tree_type *complex_region);
/**

View File

@ -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;
}
}
}

View File

@ -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<cplx_trans_type> m_trans_stack;
@ -876,7 +877,7 @@ private:
mutable std::vector<const cell_type *> m_cells;
mutable std::vector<box_tree_type> m_local_complex_region_stack;
mutable std::vector<box_type> m_local_region_stack;
mutable std::vector<bool> m_skip_shapes_stack;
mutable std::vector<bool> m_skip_shapes_stack, m_skip_shapes_member_stack;
mutable bool m_needs_reinit;
mutable size_t m_inst_quad_id;
mutable std::vector<size_t> 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

View File

@ -756,15 +756,25 @@ namespace {
: public db::RecursiveShapeReceiver
{
public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
FlatPusher (std::set<db::Box> *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<std::string> 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<db::Box> *mp_boxes;
std::set<db::Box> 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 &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)
{
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 &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)
{
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 &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)
{
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<unsigned int> 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<db::Layout> 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)
{

View File

@ -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 ()) {