diff --git a/src/db/db/dbLayoutQuery.cc b/src/db/db/dbLayoutQuery.cc index 8af7c679f..bf0017292 100644 --- a/src/db/db/dbLayoutQuery.cc +++ b/src/db/db/dbLayoutQuery.cc @@ -177,6 +177,16 @@ public: return ! m_needs_eval && m_pattern.is_const (); } + bool needs_eval () const + { + return m_needs_eval; + } + + const std::string &pattern () const + { + return m_pattern.pattern (); + } + private: tl::GlobPattern m_pattern; tl::Expression m_expression; @@ -502,6 +512,11 @@ public: bool cell_matches (db::cell_index_type ci) { + // prefilter with the cell objectives + if (! objectives ().wants_all_cells () && ! objectives ().wants_cell (ci)) { + return false; + } + if (m_pattern.is_catchall ()) { return true; } else if (m_cell_index != std::numeric_limits::max ()) { @@ -518,6 +533,58 @@ public: } } + virtual void do_init () + { + if (m_pattern.is_catchall () || m_pattern.needs_eval ()) { + + if (! objectives ().wants_all_cells ()) { + + // wildcard or unknown filter: include the parent cells if specific child cells are looked for + + int levels = 1; + for (size_t i = 0; i < followers ().size (); ++i) { + if (followers ()[i] == 0) { + // this is a sign of recursion - collect caller cells from all levels. + levels = -1; + } + } + + // this means, one follower wants only certain cells. We can optimize by only checking for potential parents + std::set callers; + for (FilterStateObjectives::cell_iterator c = objectives ().begin_cells (); c != objectives ().end_cells (); ++c) { + layout ()->cell (*c).collect_caller_cells (callers, levels); + } + + for (std::set::const_iterator c = callers.begin (); c != callers.end (); ++c) { + objectives ().request_cell (*c); + } + + } + + } else if (m_pattern.is_const ()) { + + objectives ().set_wants_all_cells (false); + + // include the cell with the name we look for into the objectives + std::pair cell_by_name = layout ()->cell_by_name (m_pattern.pattern ().c_str ()); + if (cell_by_name.first) { + objectives ().request_cell (cell_by_name.second); + } + + } else { + + objectives ().set_wants_all_cells (false); + + // include all matching cells into the objectives + for (db::Layout::const_iterator c = layout ()->begin (); c != layout ()->end(); ++c) { + if (m_pattern.match (layout ()->cell_name (c->cell_index()))) { + objectives ().request_cell (c->cell_index ()); + } + } + + } + } + virtual void reset (FilterStateBase *previous) { FilterStateBase::reset (previous); @@ -1999,6 +2066,7 @@ LayoutQueryIterator::init () { std::vector f; mp_root_state = mp_q->root ().create_state (f, mp_layout, m_eval, false); + mp_root_state->init (); mp_root_state->reset (0); m_state.push_back (mp_root_state); @@ -2866,6 +2934,56 @@ FilterBracket::optimize () // TODO: implement } +// -------------------------------------------------------------------------------- +// FilterStateObjectives implementation + +FilterStateObjectives::FilterStateObjectives () + : m_wants_all_cells (false) +{ + // .. nothing yet .. +} + +FilterStateObjectives FilterStateObjectives::everything () +{ + FilterStateObjectives all; + all.set_wants_all_cells (true); + return all; +} + +FilterStateObjectives & +FilterStateObjectives::operator+= (const FilterStateObjectives &other) +{ + if (! m_wants_all_cells) { + m_wants_all_cells = other.m_wants_all_cells; + if (! m_wants_all_cells) { + m_wants_cells.insert (other.m_wants_cells.begin (), other.m_wants_cells.end ()); + } + } + + return *this; +} + +void +FilterStateObjectives::set_wants_all_cells (bool f) +{ + m_wants_cells.clear (); + m_wants_all_cells = f; +} + +void +FilterStateObjectives::request_cell (db::cell_index_type ci) +{ + if (! m_wants_all_cells) { + m_wants_cells.insert (ci); + } +} + +bool +FilterStateObjectives::wants_cell (db::cell_index_type ci) const +{ + return m_wants_cells.find (ci) != m_wants_cells.end (); +} + // -------------------------------------------------------------------------------- // FilterStateBase implementation @@ -2874,6 +2992,35 @@ FilterStateBase::FilterStateBase (const FilterBase *filter, db::Layout *layout, { } +void +FilterStateBase::init (bool recursive) +{ + if (m_followers.empty ()) { + + m_objectives = FilterStateObjectives::everything (); + + } else { + + for (std::vector::const_iterator f = m_followers.begin (); f != m_followers.end (); ++f) { + if (*f) { + if (recursive) { + (*f)->init (); + } + m_objectives += (*f)->objectives (); + } + } + + } + + do_init (); +} + +void +FilterStateBase::do_init () +{ + // .. nothing yet .. +} + void FilterStateBase::dump () const { @@ -2903,6 +3050,7 @@ FilterStateBase::child () const if (! b && mp_filter && mp_layout) { // dynamically create a new recursive state execution graph snippet if required b = mp_filter->create_state (m_followers, mp_layout, *mp_eval, true); + b->init (false); m_followers [m_follower] = b; } diff --git a/src/db/db/dbLayoutQuery.h b/src/db/db/dbLayoutQuery.h index 48dd5e516..a50f58bd6 100644 --- a/src/db/db/dbLayoutQuery.h +++ b/src/db/db/dbLayoutQuery.h @@ -259,6 +259,44 @@ private: FilterStateBase *create_state_helper (std::map &fmap, const FilterBase *child, FilterStateBase *closure_state, db::Layout *layout, tl::Eval &eval) const; }; +/** + * @brief A structure representing optimization hints for the states + */ +struct DB_PUBLIC FilterStateObjectives +{ +public: + typedef std::set::const_iterator cell_iterator; + + FilterStateObjectives (); + + FilterStateObjectives &operator+= (const FilterStateObjectives &other); + + void set_wants_all_cells (bool f); + bool wants_all_cells () const + { + return m_wants_all_cells; + } + + void request_cell (db::cell_index_type ci); + bool wants_cell (db::cell_index_type ci) const; + + cell_iterator begin_cells () const + { + return m_wants_cells.begin (); + } + + cell_iterator end_cells () const + { + return m_wants_cells.end (); + } + + static FilterStateObjectives everything (); + +private: + bool m_wants_all_cells; + std::set m_wants_cells; +}; + /** * @brief A base class for the state objects * @@ -280,6 +318,14 @@ public: */ virtual ~FilterStateBase () { } + /** + * @brief Initializes the filter state object + * + * This method is called after the state graph has been created. It will initialize all followers + * and the call the virtual "do_init" method. + */ + void init (bool recursive = true); + /** * @brief Reset the iterator * @@ -378,6 +424,21 @@ public: */ virtual void dump () const; +protected: + /** + * @brief Performs the actual initialization + * + * The main intention of this method is to specify optimization hints + * for the objectives. Before this method is called the objectives are + * initialized as the common objectives of all followers. + */ + virtual void do_init (); + + FilterStateObjectives &objectives () + { + return m_objectives; + } + private: friend class LayoutQueryIterator; @@ -389,6 +450,7 @@ private: db::Layout *mp_layout; size_t m_follower; tl::Eval *mp_eval; + FilterStateObjectives m_objectives; void proceed (bool skip); }; diff --git a/src/db/unit_tests/dbLayoutQuery.cc b/src/db/unit_tests/dbLayoutQueryTests.cc similarity index 100% rename from src/db/unit_tests/dbLayoutQuery.cc rename to src/db/unit_tests/dbLayoutQueryTests.cc diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index f3e14367f..2ebabf6c6 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -29,7 +29,6 @@ SOURCES = \ dbLayout.cc \ dbLayoutDiff.cc \ dbLayoutUtils.cc \ - dbLayoutQuery.cc \ dbLibraries.cc \ dbMatrix.cc \ dbObject.cc \ @@ -72,7 +71,8 @@ SOURCES = \ dbDeepEdgePairsTests.cc \ dbNetlistCompareTests.cc \ dbNetlistReaderTests.cc \ - dbLayoutVsSchematicTests.cc + dbLayoutVsSchematicTests.cc \ + dbLayoutQueryTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC