From e603b7abe024fd478b7afc9332a8932439de0b4a Mon Sep 17 00:00:00 2001 From: James Cherry Date: Wed, 24 Jun 2026 16:55:51 -0700 Subject: [PATCH] dynamic loop do not use search pred Signed-off-by: James Cherry --- graph/Graph.cc | 12 ++- include/sta/Search.hh | 16 ++-- include/sta/SearchPred.hh | 8 +- search/PathEnum.cc | 38 +++++++-- search/Search.cc | 159 +++++++++++++++++++++----------------- 5 files changed, 140 insertions(+), 93 deletions(-) diff --git a/graph/Graph.cc b/graph/Graph.cc index 92775d57..e2123cf2 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -585,7 +585,8 @@ Graph::visitFanouts(Vertex *vertex, edge; edge = this->edge(edge->vertex_out_next_)) { Vertex *to_vertex = this->vertex(edge->to_); - if (pred->searchThru(edge) && pred->searchTo(to_vertex)) + if (pred->searchThru(edge) + && pred->searchTo(to_vertex)) fn(to_vertex); } } @@ -601,7 +602,8 @@ Graph::visitFanoutEdges(Vertex *vertex, edge; edge = this->edge(edge->vertex_out_next_)) { Vertex *to_vertex = this->vertex(edge->to_); - if (pred->searchThru(edge) && pred->searchTo(to_vertex)) + if (pred->searchThru(edge) + && pred->searchTo(to_vertex)) fn(edge, to_vertex); } } @@ -617,7 +619,8 @@ Graph::visitFanins(Vertex *vertex, edge; edge = this->edge(edge->vertex_in_next_)) { Vertex *from_vertex = this->vertex(edge->from_); - if (pred->searchThru(edge) && pred->searchFrom(from_vertex)) + if (pred->searchThru(edge) + && pred->searchFrom(from_vertex)) fn(from_vertex); } } @@ -633,7 +636,8 @@ Graph::visitFaninEdges(Vertex *vertex, edge; edge = this->edge(edge->vertex_in_next_)) { Vertex *from_vertex = this->vertex(edge->from_); - if (pred->searchThru(edge) && pred->searchFrom(from_vertex)) + if (pred->searchThru(edge) + && pred->searchFrom(from_vertex)) fn(edge, from_vertex); } } diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 8122752e..1fff5663 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -284,8 +284,8 @@ public: Vertex *vertex, const Mode *mode, TagGroupBldr *tag_bldr); - void enqueueLatchDataOutputs(Vertex *vertex); - void enqueueLatchOutput(Vertex *vertex); + void postponeLatchDataOutputs(Vertex *vertex); + void postponeArrivals(Vertex *vertex); void enqueuePendingClkFanouts(); void postponeClkFanouts(Vertex *vertex); void seedRequired(Vertex *vertex); @@ -590,7 +590,7 @@ protected: // Search predicates. SearchPred *search_thru_; - SearchAdj *search_adj_; + SearchPred *search_adj_; EvalPred *eval_pred_; // Some arrivals exist. @@ -647,11 +647,11 @@ protected: std::mutex tag_group_lock_; // Latches data outputs to queue on the next search pass. - VertexSet pending_latch_outputs_; - std::mutex pending_latch_outputs_lock_; + VertexSet postponed_arrivals_; + std::mutex postponed_arrivals_lock_; // Clock network endpoints where arrival search was suppended by findClkArrivals(). - VertexSet pending_clk_endpoints_; - std::mutex pending_clk_endpoints_lock_; + VertexSet postponed_clk_endpoints_; + std::mutex postponed_clk_endpoints_lock_; VertexSet endpoints_; bool endpoints_initialized_{false}; @@ -802,6 +802,8 @@ protected: void pruneCrprArrivals(); void constrainedRequiredsInvalid(Vertex *vertex, bool is_clk); + bool hasPendingLoopPaths(Edge *edge) const; + bool always_to_endpoints_; bool always_save_prev_paths_; bool clks_only_; diff --git a/include/sta/SearchPred.hh b/include/sta/SearchPred.hh index 9bcdf9b8..378e8655 100644 --- a/include/sta/SearchPred.hh +++ b/include/sta/SearchPred.hh @@ -51,19 +51,19 @@ public: // Search is allowed from from_vertex. virtual bool searchFrom(const Vertex *from_vertex, const Mode *mode) const = 0; - bool searchFrom(const Vertex *from_vertex) const; + virtual bool searchFrom(const Vertex *from_vertex) const; // Search is allowed through edge. // from/to pins are NOT checked. // inst can be either the from_pin or to_pin instance because it // is only referenced when they are the same (non-wire edge). virtual bool searchThru(Edge *edge, const Mode *mode) const = 0; - bool searchThru(Edge *edge) const; + virtual bool searchThru(Edge *edge) const; // Search is allowed to to_pin. virtual bool searchTo(const Vertex *to_vertex, const Mode *mode) const = 0; - bool searchTo(const Vertex *to_vertex) const; - void copyState(const StaState *sta); + virtual bool searchTo(const Vertex *to_vertex) const; + virtual void copyState(const StaState *sta); protected: const StaState *sta_; diff --git a/search/PathEnum.cc b/search/PathEnum.cc index e433c703..e0a3ec20 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -238,6 +238,28 @@ PathEnum::reportDiversionPath(Diversion *div) using VisitedFanins = std::set>; using VertexEdge = std::pair; +class EnumPred : public EvalPred +{ +public: + EnumPred(const StaState *sta); + bool searchThru(Edge *edge, + const Mode *mode) const override; +}; + +EnumPred::EnumPred(const StaState *sta) : + EvalPred(sta) +{ +} + +bool +EnumPred::searchThru(Edge *edge, + const Mode *mode) const +{ + // Do not enum paths across disabled loop edges. + return EvalPred::searchThru(edge, mode) + && !edge->isDisabledLoop(); +} + class PathEnumFaninVisitor : public PathVisitor { public: @@ -247,6 +269,7 @@ public: bool unique_edges, PathEnum *path_enum); PathEnumFaninVisitor(const PathEnumFaninVisitor &visitor); + virtual ~PathEnumFaninVisitor(); VertexVisitor *copy() const override; void visitFaninPathsThru(Path *before_div, Vertex *prev_vertex, @@ -311,7 +334,7 @@ PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end, bool unique_pins, bool unique_edges, PathEnum *path_enum) : - PathVisitor(path_enum), + PathVisitor(new EnumPred(path_enum), false, path_enum), path_end_(path_end), before_div_(before_div), unique_pins_(unique_pins), @@ -334,6 +357,11 @@ PathEnumFaninVisitor::PathEnumFaninVisitor(const PathEnumFaninVisitor &visitor) { } +PathEnumFaninVisitor::~PathEnumFaninVisitor() +{ + delete pred_; +} + VertexVisitor * PathEnumFaninVisitor::copy() const { @@ -655,10 +683,10 @@ PathEnum::makeDivertedPath(Path *path, Path *prev_copy = nullptr; while (p) { // prev_path made in next pass. - Path *copy = - new Path(p->vertex(this), p->tag(this), p->arrival(), - // Replaced on next pass. - p->prevPath(), p->prevEdge(this), p->prevArc(this), true, this); + Path *copy = new Path(p->vertex(this), p->tag(this), p->arrival(), + // Replaced on next pass. + p->prevPath(), p->prevEdge(this), p->prevArc(this), + true, this); search_->saveEnumPath(copy); if (prev_copy) prev_copy->setPrevPath(copy); diff --git a/search/Search.cc b/search/Search.cc index ae23c681..d1de9c1e 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -95,8 +95,8 @@ EvalPred::searchThru(Edge *edge, { const TimingRole *role = edge->role(); return SearchPred0::searchThru(edge, mode) - && (sta_->variables()->dynamicLoopBreaking() || !edge->isDisabledLoop()) - && (search_thru_latches_ || role->isLatchDtoQ() + && (search_thru_latches_ + || role->isLatchDtoQ() || sta_->latches()->latchDtoQState(edge, mode) == LatchEnableState::open); } @@ -133,54 +133,56 @@ bool SearchThru::searchThru(Edge *edge, const Mode *mode) const { - return EvalPred::searchThru(edge, mode) && !edge->role()->isLatchDtoQ(); + return EvalPred::searchThru(edge, mode) + && !edge->role()->isLatchDtoQ(); } //////////////////////////////////////////////////////////////// // SearchAdj is mode independent. Search unless -// disabled to break combinational loop // latch D->Q edge // timing check edge -// dynamic loop breaking pending tags +// register set/clear +// bidirect load->driver class SearchAdj : public SearchPred { public: - SearchAdj(TagGroupBldr *tag_bldr, - const StaState *sta); + SearchAdj(const StaState *sta); + bool searchFrom(const Vertex *from_vertex) const override; bool searchFrom(const Vertex *from_vertex, const Mode *mode) const override; + bool searchThru(Edge *edge) const override; bool searchThru(Edge *edge, const Mode *mode) const override; + bool searchTo(const Vertex *to_vertex) const override; bool searchTo(const Vertex *to_vertex, const Mode *mode) const override; protected: - bool loopEnabled(Edge *edge) const; - bool hasPendingLoopPaths(Edge *edge) const; - - TagGroupBldr *tag_bldr_; const StaState *sta_; }; -SearchAdj::SearchAdj(TagGroupBldr *tag_bldr, - const StaState *sta) : +SearchAdj::SearchAdj(const StaState *sta) : SearchPred(sta), - tag_bldr_(tag_bldr), sta_(sta) { } bool -SearchAdj::searchFrom(const Vertex * /* from_vertex */, +SearchAdj::searchFrom(const Vertex *) const +{ + return true; +} + +bool +SearchAdj::searchFrom(const Vertex *, const Mode *) const { return true; } bool -SearchAdj::searchThru(Edge *edge, - const Mode *) const +SearchAdj::searchThru(Edge *edge) const { const TimingRole *role = edge->role(); const Variables *variables = sta_->variables(); @@ -189,42 +191,24 @@ SearchAdj::searchThru(Edge *edge, // Register/latch preset/clr edges are disabled by default. || (role == TimingRole::regSetClr() && !variables->presetClrArcsEnabled()) - || sta_->isDisabledBidirectInstPath(edge) - || (edge->isDisabledLoop() - && !(variables->dynamicLoopBreaking() && hasPendingLoopPaths(edge)))); + || sta_->isDisabledBidirectInstPath(edge)); } bool -SearchAdj::loopEnabled(Edge *edge) const +SearchAdj::searchThru(Edge *edge, + const Mode *) const { - return !edge->isDisabledLoop() - || (sta_->variables()->dynamicLoopBreaking() && hasPendingLoopPaths(edge)); + return searchThru(edge); } bool -SearchAdj::hasPendingLoopPaths(Edge *edge) const +SearchAdj::searchTo(const Vertex *) const { - if (tag_bldr_ && tag_bldr_->hasLoopTag()) { - const Graph *graph = sta_->graph(); - Search *search = sta_->search(); - Vertex *from_vertex = edge->from(graph); - TagGroup *prev_tag_group = search->tagGroup(from_vertex); - for (auto const [from_tag, path_index] : tag_bldr_->pathIndexMap()) { - if (from_tag->isLoop()) { - // Loop false path exceptions apply to rise/fall edges so to_rf - // does not matter. - Tag *to_tag = search->thruTag(from_tag, edge, RiseFall::rise(), nullptr); - if (to_tag - && (prev_tag_group == nullptr || !prev_tag_group->hasTag(from_tag))) - return true; - } - } - } - return false; + return true; } bool -SearchAdj::searchTo(const Vertex * /* to_vertex */, +SearchAdj::searchTo(const Vertex *, const Mode *) const { return true; @@ -236,8 +220,7 @@ Search::Search(StaState *sta) : StaState(sta), search_thru_(new SearchThru(this)), - search_adj_(new SearchAdj(nullptr, - this)), + search_adj_(new SearchAdj(this)), eval_pred_(new EvalPred(this)), invalid_arrivals_(makeVertexSet(this)), @@ -247,9 +230,7 @@ Search::Search(StaState *sta) : arrival_visitor_(new ArrivalVisitor(this)), invalid_requireds_(makeVertexSet(this)), - required_iter_(new BfsBkwdIterator(BfsIndex::required, - search_adj_, - this)), + required_iter_(new BfsBkwdIterator(BfsIndex::required, search_adj_, this)), invalid_tns_(makeVertexSet(this)), clk_info_set_(new ClkInfoSet(ClkInfoLess(this))), @@ -261,8 +242,8 @@ Search::Search(StaState *sta) : tag_group_capacity_(tag_capacity_), tag_groups_(new TagGroup *[tag_group_capacity_]), tag_group_set_(new TagGroupSet(tag_group_capacity_)), - pending_latch_outputs_(makeVertexSet(this)), - pending_clk_endpoints_(makeVertexSet(this)), + postponed_arrivals_(makeVertexSet(this)), + postponed_clk_endpoints_(makeVertexSet(this)), endpoints_(makeVertexSet(this)), invalid_endpoints_(makeVertexSet(this)), @@ -326,8 +307,8 @@ Search::clear() deletePathGroups(); deletePaths(); deleteTags(); - pending_latch_outputs_.clear(); - pending_clk_endpoints_.clear(); + postponed_arrivals_.clear(); + postponed_clk_endpoints_.clear(); deleteFilter(); found_downstream_clk_pins_ = false; } @@ -655,10 +636,10 @@ Search::findFilteredArrivals(bool thru_latches) int arrival_count = arrival_iter_->visitParallel(max_level, arrival_visitor_); debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count); - have_pending_latch_outputs = !pending_latch_outputs_.empty(); - for (Vertex *latch_output : pending_latch_outputs_) + have_pending_latch_outputs = !postponed_arrivals_.empty(); + for (Vertex *latch_output : postponed_arrivals_) arrival_visitor_->visit(latch_output, true); - pending_latch_outputs_.clear(); + postponed_arrivals_.clear(); deleteTagsPrev(); } @@ -997,29 +978,30 @@ Search::findAllArrivals(bool thru_latches, findArrivals1(levelize_->maxLevel()); - have_pending_latch_outputs = !pending_latch_outputs_.empty(); - for (Vertex *latch_output : pending_latch_outputs_) + have_pending_latch_outputs = !postponed_arrivals_.empty(); + for (Vertex *latch_output : postponed_arrivals_) arrival_visitor_->visit(latch_output, true); - pending_latch_outputs_.clear(); + postponed_arrivals_.clear(); } } +// Pick up where the search stopped at the clock network boundary. void Search::enqueuePendingClkFanouts() { - for (Vertex *vertex : pending_clk_endpoints_) { + for (Vertex *vertex : postponed_clk_endpoints_) { debugPrint(debug_, "search", 2, "enqueue clk fanout {}", vertex->to_string(this)); arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_); } - pending_clk_endpoints_.clear(); + postponed_clk_endpoints_.clear(); } void Search::postponeClkFanouts(Vertex *vertex) { - LockGuard lock(pending_clk_endpoints_lock_); - pending_clk_endpoints_.insert(vertex); + LockGuard lock(postponed_clk_endpoints_lock_); + postponed_clk_endpoints_.insert(vertex); } void @@ -1089,7 +1071,7 @@ ArrivalVisitor::init0() { tag_bldr_ = new TagGroupBldr(true, this); tag_bldr_no_crpr_ = new TagGroupBldr(false, this); - adj_pred_ = new SearchAdj(tag_bldr_, this); + adj_pred_ = new SearchAdj(this); } void @@ -1133,7 +1115,7 @@ void ArrivalVisitor::visit(Vertex *vertex) { if (network_->isLatchOutput(vertex->pin())) - search_->enqueueLatchOutput(vertex); + search_->postponeArrivals(vertex); else visit(vertex, false); } @@ -1167,15 +1149,25 @@ ArrivalVisitor::visit(Vertex *vertex, // previous eval pass enqueue the latch outputs to be re-evaled on the // next pass. if (arrivals_changed && network_->isLatchData(pin)) - search_->enqueueLatchDataOutputs(vertex); + search_->postponeLatchDataOutputs(vertex); if ((always_to_endpoints_ || arrivals_changed)) { if (clks_only_ && vertex->isRegClk()) { debugPrint(debug_, "search", 3, "postponing clk fanout"); search_->postponeClkFanouts(vertex); } - else - search_->arrivalIterator()->enqueueAdjacentVertices(vertex, adj_pred_); + else { + graph_->visitFanoutEdges(vertex, adj_pred_, + [this] (Edge *edge, + Vertex *fanout) { + if (edge->isDisabledLoop()) { + if (hasPendingLoopPaths(edge)) + search_->postponeArrivals(fanout); + } + else + search_->arrivalIterator()->enqueue(fanout); + }); + } } if (arrivals_changed) { debugPrint(debug_, "search", 4, "arrivals changed"); @@ -1185,6 +1177,26 @@ ArrivalVisitor::visit(Vertex *vertex, } } +bool +ArrivalVisitor::hasPendingLoopPaths(Edge *edge) const +{ + if (tag_bldr_ && tag_bldr_->hasLoopTag()) { + Vertex *from_vertex = edge->from(graph_); + TagGroup *prev_tag_group = search_->tagGroup(from_vertex); + for (auto const [from_tag, path_index] : tag_bldr_->pathIndexMap()) { + if (from_tag->isLoop()) { + // Loop false path exceptions apply to rise/fall edges so to_rf + // does not matter. + Tag *to_tag = search_->thruTag(from_tag, edge, RiseFall::rise(), nullptr); + if (to_tag + && (prev_tag_group == nullptr || !prev_tag_group->hasTag(from_tag))) + return true; + } + } + } + return false; +} + void ArrivalVisitor::seedArrivals(Vertex *vertex) { @@ -1385,24 +1397,24 @@ ArrivalVisitor::pruneCrprArrivals() } void -Search::enqueueLatchDataOutputs(Vertex *latch_data) +Search::postponeLatchDataOutputs(Vertex *latch_data) { VertexOutEdgeIterator edge_iter(latch_data, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); if (edge->role() == TimingRole::latchDtoQ()) { Vertex *out_vertex = edge->to(graph_); - LockGuard lock(pending_latch_outputs_lock_); - pending_latch_outputs_.insert(out_vertex); + LockGuard lock(postponed_arrivals_lock_); + postponed_arrivals_.insert(out_vertex); } } } void -Search::enqueueLatchOutput(Vertex *vertex) +Search::postponeArrivals(Vertex *vertex) { - LockGuard lock(pending_latch_outputs_lock_); - pending_latch_outputs_.insert(vertex); + LockGuard lock(postponed_arrivals_lock_); + postponed_arrivals_.insert(vertex); } void @@ -1995,7 +2007,8 @@ PathVisitor::visitEdge(const Pin *from_pin, Path *from_path = from_iter.next(); const Mode *mode = from_path->mode(this); if (mode == prev_mode - || (pred_->searchFrom(from_vertex, mode) && pred_->searchThru(edge, mode) + || (pred_->searchFrom(from_vertex, mode) + && pred_->searchThru(edge, mode) && pred_->searchTo(to_vertex, mode))) { prev_mode = mode; const MinMax *min_max = from_path->minMax(this);