diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 6c821dab..f48ee3af 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -395,7 +395,7 @@ GraphDelayCalc::seedRootSlew(Vertex *vertex, seedDrvrSlew(vertex, arc_delay_calc); else seedLoadSlew(vertex); - iter_->enqueueAdjacentVertices(vertex); + iter_->enqueueFanout(vertex); } void @@ -703,7 +703,7 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex, // change when non-incremental to stride past annotations. if (!incremental_ || loadSlewsChanged(load_slews_prev, load_pin_index_map)) - iter_->enqueueAdjacentVertices(vertex); + iter_->enqueueFanout(vertex); } } else { @@ -711,7 +711,7 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex, enqueueTimingChecksEdges(vertex); // Enqueue driver vertices from this input load. if (propagate) - iter_->enqueueAdjacentVertices(vertex); + iter_->enqueueFanout(vertex); } } // Bidirect port drivers are enqueued by their load vertex in diff --git a/graph/Graph.cc b/graph/Graph.cc index 589e1fa0..942e1951 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -581,9 +581,9 @@ Graph::visitFanouts(Vertex *vertex, const VertexFn &fn) { if (pred->searchFrom(vertex)) { - for (Edge *edge = this->edge(vertex->out_edges_); - edge; - edge = this->edge(edge->vertex_out_next_)) { + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); Vertex *to_vertex = this->vertex(edge->to_); if (pred->searchThru(edge) && pred->searchTo(to_vertex)) @@ -598,9 +598,9 @@ Graph::visitFanoutEdges(Vertex *vertex, const EdgeFn &fn) { if (pred->searchFrom(vertex)) { - for (Edge *edge = this->edge(vertex->out_edges_); - edge; - edge = this->edge(edge->vertex_out_next_)) { + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); Vertex *to_vertex = this->vertex(edge->to_); if (pred->searchThru(edge) && pred->searchTo(to_vertex)) @@ -615,9 +615,9 @@ Graph::visitFanins(Vertex *vertex, const VertexFn &fn) { if (pred->searchFrom(vertex)) { - for (Edge *edge = this->edge(vertex->in_edges_); - edge; - edge = this->edge(edge->vertex_in_next_)) { + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); Vertex *from_vertex = this->vertex(edge->from_); if (pred->searchThru(edge) && pred->searchFrom(from_vertex)) @@ -632,9 +632,9 @@ Graph::visitFaninEdges(Vertex *vertex, const EdgeFn &fn) { if (pred->searchFrom(vertex)) { - for (Edge *edge = this->edge(vertex->in_edges_); - edge; - edge = this->edge(edge->vertex_in_next_)) { + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); Vertex *from_vertex = this->vertex(edge->from_); if (pred->searchThru(edge) && pred->searchFrom(from_vertex)) diff --git a/include/sta/Bfs.hh b/include/sta/Bfs.hh index 5c11ab1c..c0c24f1e 100644 --- a/include/sta/Bfs.hh +++ b/include/sta/Bfs.hh @@ -24,6 +24,7 @@ #pragma once +#include #include #include @@ -38,6 +39,8 @@ class SearchPred; class BfsFwdIterator; class BfsBkwdIterator; +using VertexFn = std::function; + // LevelQueue is a vector of vertex vectors indexed by logic level. using LevelQueue = std::vector; @@ -50,26 +53,23 @@ using LevelQueue = std::vector; // Vertices are marked as being in the queue by using a flag on // the vertex indexed by bfs_index. A unique flag is only needed // if the BFS in in use when other BFS's are simultaneously in use. -class BfsIterator : public StaState, - public Iterator +class BfsIterator : public StaState { public: // Make sure that the BFS queue is deep enough for the max logic level. void ensureSize(); // Reset to virgin state. void clear(); + // Apply fn to each vertex and clear. + void clear(const VertexFn &fn); [[nodiscard]] bool empty() const; // Enqueue a vertex to search from. void enqueue(Vertex *vertex); // Enqueue vertices adjacent to a vertex. - void enqueueAdjacentVertices(Vertex *vertex); + virtual void enqueueAdjacentVertices(Vertex *vertex) = 0; virtual void enqueueAdjacentVertices(Vertex *vertex, - const Mode *mode); - virtual void enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred, const Mode *mode) = 0; - virtual void enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred) = 0; + [[nodiscard]] bool inQueue(Vertex *vertex); void checkInQueue(Vertex *vertex); // Notify iterator that vertex will be deleted. @@ -77,10 +77,6 @@ public: void remove(Vertex *vertex); void reportEntries() const; - bool hasNext() override; - bool hasNext(Level to_level); - Vertex *next() override; - // Apply visitor to all vertices in the queue in level order. // Returns the number of vertices that are visited. virtual int visit(Level to_level, @@ -91,6 +87,10 @@ public: int visitParallel(Level to_level, VertexVisitor *visitor); + bool hasNext(); + bool hasNext(Level to_level); + Vertex *next(); + protected: BfsIterator(BfsIndex bfs_index, Level level_min, @@ -104,10 +104,10 @@ protected: virtual bool levelLessOrEqual(Level level1, Level level2) const = 0; virtual void incrLevel(Level &level) const = 0; - void findNext(Level to_level); void deleteEntries(); void checkLevel(Vertex *vertex, Level level); + void findNext(Level to_level); BfsIndex bfs_index_; Level level_min_; @@ -131,12 +131,13 @@ public: SearchPred *search_pred, StaState *sta); ~BfsFwdIterator() override; + void enqueueAdjacentVertices(Vertex *vertex) override; void enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred) override; - void enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred, const Mode *mode) override; using BfsIterator::enqueueAdjacentVertices; + void enqueueFanout(Vertex *vertex); + void enqueueFanout(Vertex *vertex, + const Mode *mode); protected: bool levelLessOrEqual(Level level1, @@ -153,14 +154,17 @@ public: SearchPred *search_pred, StaState *sta); ~BfsBkwdIterator() override; + void enqueueAdjacentVertices(Vertex *vertex) override; void enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred) override; - void enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred, const Mode *mode) override; using BfsIterator::enqueueAdjacentVertices; + void enqueueFanin(Vertex *vertex); + void enqueueFanin(Vertex *vertex, + const Mode *mode); protected: + void enqueueFanin(Vertex *vertex, + SearchPred *search_pred); bool levelLessOrEqual(Level level1, Level level2) const override; bool levelLess(Level level1, diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 539c9895..5661a387 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -286,8 +286,6 @@ public: TagGroupBldr *tag_bldr); void postponeLatchDataOutputs(Vertex *vertex); void postponeArrivals(Vertex *vertex); - void enqueuePendingClkFanouts(); - void postponeClkFanouts(Vertex *vertex); void seedRequired(Vertex *vertex); void seedRequiredEnqueueFanin(Vertex *vertex); void seedInputDelayArrival(const Pin *pin, @@ -503,12 +501,12 @@ protected: bool is_segment_start, const MinMax *min_max, Scene *scene); - void seedClkVertexArrivals(); - void findClkArrivals1(); + void enqueueClkRoots(); + void enqueueInvalidClks(); - void findAllArrivals(bool thru_latches, - bool clks_only); + void findAllArrivals(bool thru_latches); void findArrivals1(Level level); + void findArrivals2(Level level); Tag *mutateTag(Tag *from_tag, const Pin *from_pin, const RiseFall *from_rf, @@ -646,12 +644,9 @@ protected: std::vector tag_group_free_indices_; std::mutex tag_group_lock_; - // Latches data outputs to queue on the next search pass. - VertexSet postponed_arrivals_; - std::mutex postponed_arrivals_lock_; - // Clock network endpoints where arrival search was suppended by findClkArrivals(). - VertexSet postponed_clk_endpoints_; - std::mutex postponed_clk_endpoints_lock_; + // Arrivals to queue on the next search pass. + VertexSet pending_arrivals_; + std::mutex pending_arrivals_lock_; VertexSet endpoints_; bool endpoints_initialized_{false}; diff --git a/search/Bfs.cc b/search/Bfs.cc index ee099344..0cf8bf37 100644 --- a/search/Bfs.cc +++ b/search/Bfs.cc @@ -70,13 +70,21 @@ BfsIterator::ensureSize() void BfsIterator::clear() +{ + clear([] (Vertex *) {}); +} + +void +BfsIterator::clear(const VertexFn &fn) { Level level = first_level_; while (levelLessOrEqual(level, last_level_)) { VertexSeq &level_vertices = queue_[level]; for (Vertex *vertex : level_vertices) { - if (vertex) + if (vertex) { vertex->setBfsInQueue(bfs_index_, false); + fn(vertex); + } } level_vertices.clear(); incrLevel(level); @@ -115,19 +123,6 @@ BfsIterator::empty() const return levelLess(last_level_, first_level_); } -void -BfsIterator::enqueueAdjacentVertices(Vertex *vertex) -{ - enqueueAdjacentVertices(vertex, search_pred_); -} - -void -BfsIterator::enqueueAdjacentVertices(Vertex *vertex, - const Mode *mode) -{ - enqueueAdjacentVertices(vertex, search_pred_, mode); -} - int BfsIterator::visit(Level to_level, VertexVisitor *visitor) @@ -217,50 +212,6 @@ BfsIterator::visitParallel(Level to_level, return visit_count; } -bool -BfsIterator::hasNext() -{ - return hasNext(last_level_); -} - -bool -BfsIterator::hasNext(Level to_level) -{ - findNext(to_level); - return levelLessOrEqual(first_level_, last_level_) - && !queue_[first_level_].empty(); -} - -Vertex * -BfsIterator::next() -{ - VertexSeq &level_vertices = queue_[first_level_]; - Vertex *vertex = level_vertices.back(); - level_vertices.pop_back(); - vertex->setBfsInQueue(bfs_index_, false); - return vertex; -} - -void -BfsIterator::findNext(Level to_level) -{ - while (levelLessOrEqual(first_level_, last_level_) - && levelLessOrEqual(first_level_, to_level)) { - VertexSeq &level_vertices = queue_[first_level_]; - // Skip null entries from deleted vertices. - while (!level_vertices.empty()) { - Vertex *vertex = level_vertices.back(); - if (vertex == nullptr) - level_vertices.pop_back(); - else { - checkLevel(vertex, first_level_); - return; - } - } - incrLevel(first_level_); - } -} - void BfsIterator::enqueue(Vertex *vertex) { @@ -340,6 +291,52 @@ BfsIterator::remove(Vertex *vertex) //////////////////////////////////////////////////////////////// +bool +BfsIterator::hasNext() +{ + return hasNext(last_level_); +} + +bool +BfsIterator::hasNext(Level to_level) +{ + findNext(to_level); + return levelLessOrEqual(first_level_, last_level_) + && !queue_[first_level_].empty(); +} + +Vertex * +BfsIterator::next() +{ + VertexSeq &level_vertices = queue_[first_level_]; + Vertex *vertex = level_vertices.back(); + level_vertices.pop_back(); + vertex->setBfsInQueue(bfs_index_, false); + return vertex; +} + +void +BfsIterator::findNext(Level to_level) +{ + while (levelLessOrEqual(first_level_, last_level_) + && levelLessOrEqual(first_level_, to_level)) { + VertexSeq &level_vertices = queue_[first_level_]; + // Skip null entries from deleted vertices. + while (!level_vertices.empty()) { + Vertex *vertex = level_vertices.back(); + if (vertex == nullptr) + level_vertices.pop_back(); + else { + checkLevel(vertex, first_level_); + return; + } + } + incrLevel(first_level_); + } +} + +//////////////////////////////////////////////////////////////// + BfsFwdIterator::BfsFwdIterator(BfsIndex bfs_index, SearchPred *search_pred, StaState *sta) : @@ -375,15 +372,46 @@ BfsFwdIterator::levelLess(Level level1, } void -BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred) +BfsFwdIterator::enqueueFanout(Vertex *vertex) { - if (search_pred->searchFrom(vertex)) { + if (search_pred_->searchFrom(vertex)) { VertexOutEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *to_vertex = edge->to(graph_); - if (search_pred->searchThru(edge) && search_pred->searchTo(to_vertex)) + if (search_pred_->searchThru(edge) + && search_pred_->searchTo(to_vertex)) + enqueue(to_vertex); + } + } +} + +void +BfsFwdIterator::enqueueFanout(Vertex *vertex, + const Mode *mode) +{ + if (search_pred_->searchFrom(vertex, mode)) { + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + Vertex *to_vertex = edge->to(graph_); + if (search_pred_->searchThru(edge, mode) + && search_pred_->searchTo(to_vertex, mode)) + enqueue(to_vertex); + } + } +} + +void +BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex) +{ + if (search_pred_->searchFrom(vertex)) { + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + Vertex *to_vertex = edge->to(graph_); + if (search_pred_->searchThru(edge) + && search_pred_->searchTo(to_vertex)) enqueue(to_vertex); } } @@ -391,16 +419,15 @@ BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex, void BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred, const Mode *mode) { - if (search_pred->searchFrom(vertex, mode)) { + if (search_pred_->searchFrom(vertex, mode)) { VertexOutEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *to_vertex = edge->to(graph_); - if (search_pred->searchThru(edge, mode) - && search_pred->searchTo(to_vertex, mode)) + if (search_pred_->searchThru(edge, mode) + && search_pred_->searchTo(to_vertex, mode)) enqueue(to_vertex); } } @@ -443,15 +470,15 @@ BfsBkwdIterator::levelLess(Level level1, } void -BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred) +BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex) { - if (search_pred->searchTo(vertex)) { + if (search_pred_->searchTo(vertex)) { VertexInEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *from_vertex = edge->from(graph_); - if (search_pred->searchFrom(from_vertex) && search_pred->searchThru(edge)) + if (search_pred_->searchFrom(from_vertex) + && search_pred_->searchThru(edge)) enqueue(from_vertex); } } @@ -459,16 +486,46 @@ BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex, void BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex, - SearchPred *search_pred, const Mode *mode) { - if (search_pred->searchTo(vertex, mode)) { + if (search_pred_->searchTo(vertex, mode)) { VertexInEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *from_vertex = edge->from(graph_); - if (search_pred->searchFrom(from_vertex, mode) - && search_pred->searchThru(edge, mode)) + if (search_pred_->searchFrom(from_vertex, mode) + && search_pred_->searchThru(edge, mode)) + enqueue(from_vertex); + } + } +} + +void +BfsBkwdIterator::enqueueFanin(Vertex *vertex) +{ + if (search_pred_->searchTo(vertex)) { + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + Vertex *from_vertex = edge->from(graph_); + if (search_pred_->searchFrom(from_vertex) + && search_pred_->searchThru(edge)) + enqueue(from_vertex); + } + } +} + +void +BfsBkwdIterator::enqueueFanin(Vertex *vertex, + const Mode *mode) +{ + if (search_pred_->searchTo(vertex, mode)) { + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + Vertex *from_vertex = edge->from(graph_); + if (search_pred_->searchFrom(from_vertex, mode) + && search_pred_->searchThru(edge, mode)) enqueue(from_vertex); } } diff --git a/search/ClkNetwork.cc b/search/ClkNetwork.cc index 93a29496..991a1821 100644 --- a/search/ClkNetwork.cc +++ b/search/ClkNetwork.cc @@ -24,7 +24,8 @@ #include "ClkNetwork.hh" -#include "Bfs.hh" +#include + #include "Debug.hh" #include "Graph.hh" #include "Mode.hh" @@ -127,7 +128,6 @@ ClkNetwork::findClkPins(bool ideal_only, { const Sdc *sdc = mode_->sdc(); ClkSearchPred srch_pred(this); - BfsFwdIterator bfs(BfsIndex::other, &srch_pred, this); for (Clock *clk : sdc->clocks()) { if (!ideal_only || !clk->isPropagated()) { @@ -136,25 +136,39 @@ ClkNetwork::findClkPins(bool ideal_only, clk_pins = new PinSet(network_); clk_pins_map_[clk] = clk_pins; } + std::queue queue; + VertexSet visited = makeVertexSet(this); + auto enqueue = [&queue, &visited] (Vertex *vertex) { + if (vertex && !visited.contains(vertex)) { + visited.insert(vertex); + queue.push(vertex); + } + }; for (const Pin *pin : clk->leafPins()) { if (!ideal_only || !sdc->isPropagatedClock(pin)) { Vertex *vertex, *bidirect_drvr_vertex; graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); - bfs.enqueue(vertex); - if (bidirect_drvr_vertex) - bfs.enqueue(bidirect_drvr_vertex); + enqueue(vertex); + enqueue(bidirect_drvr_vertex); } } - while (bfs.hasNext()) { - Vertex *vertex = bfs.next(); + while (!queue.empty()) { + Vertex *vertex = queue.front(); + queue.pop(); const Pin *pin = vertex->pin(); if (!ideal_only || !sdc->isPropagatedClock(pin)) { clk_pins->insert(pin); ClockSet &pin_clks = pin_clks_map[pin]; pin_clks.insert(clk); - bfs.enqueueAdjacentVertices(vertex); + graph_->visitFanouts(vertex, &srch_pred, + [&queue, &visited] (Vertex *fanout) { + if (!visited.contains(fanout)) { + visited.insert(fanout); + queue.push(fanout); + } + }); } } } diff --git a/search/Genclks.cc b/search/Genclks.cc index 7b16a51f..2aad7074 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -271,7 +271,6 @@ Genclks::ensureMaster(Clock *gclk, // Search backward from generated clock source pin to a clock pin. GenClkMasterSearchPred srch_pred(this); VertexQueue master_queue; - VertexSet visited = makeVertexSet(this); VertexSet src_vertices = makeVertexSet(this); gclk->srcPinVertices(src_vertices, network_, graph_); for (Vertex *vertex : src_vertices) @@ -279,28 +278,25 @@ Genclks::ensureMaster(Clock *gclk, while (!master_queue.empty()) { Vertex *vertex = master_queue.front(); master_queue.pop(); - if (!visited.contains(vertex)) { - visited.insert(vertex); - Pin *pin = vertex->pin(); - if (sdc->isLeafPinClock(pin)) { - ClockSet *master_clks = sdc->findLeafPinClocks(pin); - if (master_clks) { - ClockSet::iterator master_iter = master_clks->begin(); - if (master_iter != master_clks->end()) { - master_clk = *master_iter++; - // Master source pin can actually be a clock source pin. - if (master_clk != gclk) { - gclk->setInferedMasterClk(master_clk); - debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(), - master_clk->name()); - master_clk_count++; - break; - } + Pin *pin = vertex->pin(); + if (sdc->isLeafPinClock(pin)) { + ClockSet *master_clks = sdc->findLeafPinClocks(pin); + if (master_clks) { + ClockSet::iterator master_iter = master_clks->begin(); + if (master_iter != master_clks->end()) { + master_clk = *master_iter++; + // Master source pin can actually be a clock source pin. + if (master_clk != gclk) { + gclk->setInferedMasterClk(master_clk); + debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(), + master_clk->name()); + master_clk_count++; + break; } } } - enqueueFanin(vertex, master_queue, srch_pred); } + enqueueFanin(vertex, master_queue, srch_pred); } } if (master_clk_count > 1) diff --git a/search/Search.cc b/search/Search.cc index 879c1247..6d19df6f 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -30,6 +30,7 @@ #include "Bfs.hh" #include "ClkInfo.hh" +#include "ClkNetwork.hh" #include "Clock.hh" #include "ContainerHelpers.hh" #include "Crpr.hh" @@ -263,8 +264,7 @@ Search::Search(StaState *sta) : tag_group_capacity_(tag_capacity_), tag_groups_(new TagGroup *[tag_group_capacity_]), tag_group_set_(new TagGroupSet(tag_group_capacity_)), - postponed_arrivals_(makeVertexSet(this)), - postponed_clk_endpoints_(makeVertexSet(this)), + pending_arrivals_(makeVertexSet(this)), endpoints_(makeVertexSet(this)), invalid_endpoints_(makeVertexSet(this)), @@ -328,8 +328,7 @@ Search::clear() deletePathGroups(); deletePaths(); deleteTags(); - postponed_arrivals_.clear(); - postponed_clk_endpoints_.clear(); + pending_arrivals_.clear(); deleteFilter(); found_downstream_clk_pins_ = false; } @@ -546,7 +545,7 @@ Search::findFilteredArrivals(ExceptionFrom *from, // These cases do not require filtered arrivals. // -from clocks // -to - findAllArrivals(thru_latches, false); + findAllArrivals(thru_latches); } // From/thrus/to are used to make a filter exception. If the last @@ -639,32 +638,36 @@ Search::deleteFilterClkInfos() void Search::findFilteredArrivals(bool thru_latches) { - filtered_arrivals_.clear(); - findArrivalsSeed(); - seedFilterStarts(); - Level max_level = levelize_->maxLevel(); // Search always_to_endpoint to search from exisiting arrivals at // fanin startpoints to reach -thru/-to endpoints. arrival_visitor_->init(true, false, eval_pred_); - enqueuePendingClkFanouts(); - bool have_pending_latch_outputs = false; - // Iterate until data arrivals at all latches stop changing. + arrival_iter_->ensureSize(); + + filtered_arrivals_.clear(); + findArrivalsSeed(); + seedFilterStarts(); + + Level max_level = levelize_->maxLevel(); + bool have_pending_arrivals = false; for (int pass = 1; - pass == 1 || (thru_latches && have_pending_latch_outputs); + pass == 1 || (thru_latches && have_pending_arrivals); pass++) { debugPrint(debug_, "search", 1, "find arrivals pass {}", pass); int arrival_count = arrival_iter_->visitParallel(max_level, arrival_visitor_); debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count); - have_pending_latch_outputs = !postponed_arrivals_.empty(); - for (Vertex *latch_output : postponed_arrivals_) - arrival_visitor_->visit(latch_output, true); - postponed_arrivals_.clear(); + // Latch D->Q and disabled loop edges have level discontinuities so their + // eval. For latches the data path crpr clk path may be evaled in another + // thread at the same time the latch D->Q edge. + // Disabled loop edges propagate pending loop paths here. + have_pending_arrivals = !pending_arrivals_.empty(); + for (Vertex *vertex : pending_arrivals_) + arrival_visitor_->visit(vertex, true); + pending_arrivals_.clear(); deleteTagsPrev(); } - arrivals_exist_ = true; } // Delete stale tag arrarys. @@ -860,14 +863,13 @@ void Search::levelsChangedBefore() { if (arrivals_exist_) { - while (arrival_iter_->hasNext()) { - Vertex *vertex = arrival_iter_->next(); + arrival_iter_->clear([this] (Vertex *vertex) { arrivalInvalid(vertex); - } - while (required_iter_->hasNext()) { - Vertex *vertex = required_iter_->next(); + }); + + required_iter_->clear([this] (Vertex *vertex) { requiredInvalid(vertex); - } + }); } } @@ -939,11 +941,16 @@ Search::requiredInvalid(Vertex *vertex) void Search::findClkArrivals() { - findAllArrivals(false, true); + debugPrint(debug_, "search", 1, "find clk arrivals"); + arrival_visitor_->init(false, true, eval_pred_); + arrival_iter_->ensureSize(); + enqueueClkRoots(); + enqueueInvalidClks(); + findArrivals2(levelize_->maxLevel()); } void -Search::seedClkVertexArrivals() +Search::enqueueClkRoots() { PinSet clk_pins(network_); findClkVertexPins(clk_pins); @@ -954,6 +961,32 @@ Search::seedClkVertexArrivals() if (bidirect_drvr_vertex) arrival_iter_->enqueue(bidirect_drvr_vertex); } + arrivals_exist_ = true; +} + +void +Search::enqueueInvalidClks() +{ + if (!invalid_arrivals_.empty()) { + for (Mode *mode : modes_) + mode->clkNetwork()->ensureClkNetwork(); + for (auto itr = invalid_arrivals_.begin(); itr != invalid_arrivals_.end();) { + Vertex *vertex = *itr; + bool is_clk = false; + for (Mode *mode : modes_) { + if (mode->clkNetwork()->isClock(vertex)) { + is_clk = true; + break; + } + } + if (is_clk) { + arrival_iter_->enqueue(vertex); + itr = invalid_arrivals_.erase(itr); + } + else + itr++; + } + } } Arrival @@ -980,51 +1013,31 @@ Search::clockInsertion(const Clock *clk, void Search::findAllArrivals() { - findAllArrivals(true, false); + findAllArrivals(true); } void -Search::findAllArrivals(bool thru_latches, - bool clks_only) +Search::findAllArrivals(bool thru_latches) { - if (!clks_only) - enqueuePendingClkFanouts(); - arrival_visitor_->init(false, clks_only, eval_pred_); - bool have_pending_latch_outputs = false; + arrival_visitor_->init(false, false, eval_pred_); + arrival_iter_->ensureSize(); + + bool have_pending_arrivals = false; // Iterate until data arrivals at all latches stop changing. for (int pass = 1; - pass == 1 || (thru_latches && have_pending_latch_outputs); + pass == 1 || (thru_latches && have_pending_arrivals); pass++) { debugPrint(debug_, "search", 1, "find arrivals pass {}", pass); findArrivals1(levelize_->maxLevel()); - have_pending_latch_outputs = !postponed_arrivals_.empty(); - for (Vertex *latch_output : postponed_arrivals_) - arrival_visitor_->visit(latch_output, true); - postponed_arrivals_.clear(); + have_pending_arrivals = !pending_arrivals_.empty(); + for (Vertex *vertex : pending_arrivals_) + arrival_visitor_->visit(vertex, true); + pending_arrivals_.clear(); } } -// Pick up where the search stopped at the clock network boundary. -void -Search::enqueuePendingClkFanouts() -{ - for (Vertex *vertex : postponed_clk_endpoints_) { - debugPrint(debug_, "search", 2, "enqueue clk fanout {}", - vertex->to_string(this)); - arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_); - } - postponed_clk_endpoints_.clear(); -} - -void -Search::postponeClkFanouts(Vertex *vertex) -{ - LockGuard lock(postponed_clk_endpoints_lock_); - postponed_clk_endpoints_.insert(vertex); -} - void Search::findArrivals() { @@ -1035,6 +1048,7 @@ void Search::findArrivals(Level level) { arrival_visitor_->init(false, false, eval_pred_); + arrival_iter_->ensureSize(); findArrivals1(level); } @@ -1043,13 +1057,19 @@ Search::findArrivals1(Level level) { debugPrint(debug_, "search", 1, "find arrivals to level {}", level); findArrivalsSeed(); + findArrivals2(level); +} + +// Caller seeds arrival_iter_. +void +Search::findArrivals2(Level level) +{ Stats stats(debug_, report_); int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_); deleteTagsPrev(); if (arrival_count > 0) deleteUnusedTagGroups(); stats.report("Find arrivals"); - arrivals_exist_ = true; debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count); } @@ -1059,15 +1079,9 @@ Search::findArrivalsSeed() if (!arrivals_seeded_) { for (const Mode *mode : modes_) mode->genclks()->ensureInsertionDelays(); - arrival_iter_->clear(); - required_iter_->clear(); seedArrivals(); arrivals_seeded_ = true; } - else { - arrival_iter_->ensureSize(); - required_iter_->ensureSize(); - } seedInvalidArrivals(); } @@ -1173,22 +1187,18 @@ ArrivalVisitor::visit(Vertex *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 { - graph_->visitFanoutEdges(vertex, search_adj_, - [this] (Edge *edge, - Vertex *fanout) { - if (edge->isDisabledLoop()) { - if (hasPendingLoopPaths(edge)) - search_->postponeArrivals(fanout); - } - else - search_->arrivalIterator()->enqueue(fanout); - }); - } + graph_->visitFanoutEdges(vertex, search_adj_, + [this, vertex] (Edge *edge, + Vertex *fanout) { + if (edge->isDisabledLoop()) { + if (hasPendingLoopPaths(edge)) + search_->postponeArrivals(fanout); + } + else if (clks_only_ && vertex->isRegClk()) + search_->arrivalInvalid(fanout); + else + search_->arrivalIterator()->enqueue(fanout); + }); } if (arrivals_changed) { debugPrint(debug_, "search", 4, "arrivals changed"); @@ -1425,8 +1435,8 @@ Search::postponeLatchDataOutputs(Vertex *latch_data) Edge *edge = edge_iter.next(); if (edge->role() == TimingRole::latchDtoQ()) { Vertex *out_vertex = edge->to(graph_); - LockGuard lock(postponed_arrivals_lock_); - postponed_arrivals_.insert(out_vertex); + LockGuard lock(pending_arrivals_lock_); + pending_arrivals_.insert(out_vertex); } } } @@ -1434,8 +1444,8 @@ Search::postponeLatchDataOutputs(Vertex *latch_data) void Search::postponeArrivals(Vertex *vertex) { - LockGuard lock(postponed_arrivals_lock_); - postponed_arrivals_.insert(vertex); + LockGuard lock(pending_arrivals_lock_); + pending_arrivals_.insert(vertex); } void @@ -1448,6 +1458,7 @@ Search::seedArrivals() for (Vertex *vertex : vertices) arrival_iter_->enqueue(vertex); + arrivals_exist_ = true; } void @@ -3160,6 +3171,7 @@ void Search::seedRequireds() { ensureDownstreamClkPins(); + required_iter_->ensureSize(); for (Vertex *vertex : endpoints()) seedRequired(vertex); requireds_seeded_ = true; @@ -3334,8 +3346,9 @@ Search::seedRequired(Vertex *vertex) required_cmp.requiredsInit(vertex, this); visit_path_ends_->visitPathEnds(vertex, &seeder); // Enqueue fanin vertices for back-propagating required times. + required_iter_->ensureSize(); if (required_cmp.requiredsSave(vertex, this)) - required_iter_->enqueueAdjacentVertices(vertex); + required_iter_->enqueueFanin(vertex); } void @@ -3347,7 +3360,7 @@ Search::seedRequiredEnqueueFanin(Vertex *vertex) visit_path_ends_->visitPathEnds(vertex, &seeder); // Enqueue fanin vertices for back-propagating required times. required_cmp.requiredsSave(vertex, this); - required_iter_->enqueueAdjacentVertices(vertex); + required_iter_->enqueueFanin(vertex); } //////////////////////////////////////////////////////////////// @@ -3455,7 +3468,7 @@ RequiredVisitor::visit(Vertex *vertex) search_->tnsInvalid(vertex); if (changed) - search_->requiredIterator()->enqueueAdjacentVertices(vertex); + search_->requiredIterator()->enqueueFanin(vertex); } bool @@ -3538,17 +3551,27 @@ void Search::ensureDownstreamClkPins() { if (!found_downstream_clk_pins_) { - // Use backward BFS from register clk pins to mark upsteam pins - // as having downstream clk pins. + // Use backward DFS from register clk pins to mark upstream pins + // as having downstream clk pins. hasDownstreamClkPin doubles as the + // visited flag since its meaning is exactly "reached here". ClkTreeSearchPred pred(this); - BfsBkwdIterator iter(BfsIndex::other, &pred, this); - for (Vertex *vertex : graph_->regClkVertices()) - iter.enqueue(vertex); - - while (iter.hasNext()) { - Vertex *vertex = iter.next(); - vertex->setHasDownstreamClkPin(true); - iter.enqueueAdjacentVertices(vertex); + std::vector stack; + for (Vertex *vertex : graph_->regClkVertices()) { + if (!vertex->hasDownstreamClkPin()) { + vertex->setHasDownstreamClkPin(true); + stack.push_back(vertex); + } + } + while (!stack.empty()) { + Vertex *vertex = stack.back(); + stack.pop_back(); + graph_->visitFanins(vertex, &pred, + [&stack] (Vertex *fanin) { + if (!fanin->hasDownstreamClkPin()) { + fanin->setHasDownstreamClkPin(true); + stack.push_back(fanin); + } + }); } } found_downstream_clk_pins_ = true;