diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 3d6180ec..ba9f1463 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -59,7 +59,6 @@ GraphDelayCalc::GraphDelayCalc(StaState *sta) : search_non_latch_pred_(new SearchPredNonLatch2(sta)), clk_pred_(new ClkTreeSearchPred(sta)), iter_(new BfsFwdIterator(BfsIndex::dcalc, search_non_latch_pred_, sta)), - multi_drvr_nets_found_(false), incremental_delay_tolerance_(0.0) { } @@ -103,7 +102,6 @@ GraphDelayCalc::clear() { delaysInvalid(); deleteMultiDrvrNets(); - multi_drvr_nets_found_ = false; } float @@ -184,7 +182,7 @@ GraphDelayCalc::deleteVertexBefore(Vertex *vertex) MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); if (multi_drvr) { // Don't bother incrementally updating MultiDrvrNet. - for (Vertex *drvr_vertex : *multi_drvr->drvrs()) + for (Vertex *drvr_vertex : multi_drvr->drvrs()) multi_drvr_net_map_.erase(drvr_vertex); delete multi_drvr; } @@ -477,7 +475,7 @@ GraphDelayCalc::findPortIndex(const LibertyCell *cell, return index; index++; } - report_->critical(1100, "port not found in cell"); + report_->critical(1100, "port not found in cell."); return 0; } @@ -655,26 +653,50 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex, MultiDrvrNet * GraphDelayCalc::findMultiDrvrNet(Vertex *drvr_vertex) { - MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); - if (multi_drvr) + // Avoid locking for single driver nets. + if (hasMultiDrvrs(drvr_vertex)) { + UniqueLock lock(multi_drvr_lock_); + MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); + if (multi_drvr) + return multi_drvr; + multi_drvr = makeMultiDrvrNet(drvr_vertex); return multi_drvr; - else { - const PinSet *drvrs = network_->drivers(drvr_vertex->pin()); - if (drvrs && drvrs->size() > 1) { - PinSet drvrs1(network_); - // Filter input ports and non-leaf drivers. - for (const Pin *pin : *drvrs) { - if (isLeafDriver(pin, network_)) - drvrs1.insert(pin); - } - MultiDrvrNet *multi_drvr = nullptr; - if (drvrs1.size() > 1) - multi_drvr = makeMultiDrvrNet(drvrs1); - return multi_drvr; - } - else - return nullptr; } + return nullptr; +} + +bool +GraphDelayCalc::hasMultiDrvrs(Vertex *drvr_vertex) +{ + Vertex *load_vertex = firstLoad(drvr_vertex); + if (load_vertex) { + int drvr_count = 0; + VertexInEdgeIterator edge_iter(load_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->isWire()) { + Vertex *drvr = edge->from(graph_); + if (isLeafDriver(drvr->pin(), network_)) + drvr_count++; + } + if (drvr_count > 1) + return true; + } + return false; + } + return false; +} + +Vertex * +GraphDelayCalc::firstLoad(Vertex *drvr_vertex) +{ + VertexOutEdgeIterator edge_iter(drvr_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *wire_edge = edge_iter.next(); + if (wire_edge->isWire()) + return wire_edge->to(graph_); + } + return nullptr; } static bool @@ -693,31 +715,41 @@ GraphDelayCalc::multiDrvrNet(const Vertex *drvr_vertex) const } MultiDrvrNet * -GraphDelayCalc::makeMultiDrvrNet(PinSet &drvr_pins) +GraphDelayCalc::makeMultiDrvrNet(Vertex *drvr_vertex) { - debugPrint(debug_, "delay_calc", 3, "multi-driver net"); - VertexSet *drvr_vertices = new VertexSet(graph_); - MultiDrvrNet *multi_drvr = new MultiDrvrNet(drvr_vertices); - Level max_drvr_level = 0; - Vertex *max_drvr = nullptr; - PinSet::Iterator pin_iter(drvr_pins); - while (pin_iter.hasNext()) { - const Pin *pin = pin_iter.next(); - Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); - debugPrint(debug_, "delay_calc", 3, " %s", - network_->pathName(pin)); - multi_drvr_net_map_[drvr_vertex] = multi_drvr; - drvr_vertices->insert(drvr_vertex); - Level drvr_level = drvr_vertex->level(); - if (max_drvr == nullptr - || drvr_level > max_drvr_level) { - max_drvr = drvr_vertex; - max_drvr_level = drvr_level; + Vertex *load_vertex = firstLoad(drvr_vertex); + if (load_vertex) { + debugPrint(debug_, "delay_calc", 3, "multi-driver net"); + MultiDrvrNet *multi_drvr = new MultiDrvrNet; + VertexSeq &drvr_vertices = multi_drvr->drvrs(); + Level max_drvr_level = 0; + Vertex *max_drvr = nullptr; + VertexInEdgeIterator edge_iter(load_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->isWire()) { + Vertex *drvr = edge->from(graph_); + const Pin *drvr_pin = drvr->pin(); + if (isLeafDriver(drvr_pin, network_)) { + debugPrint(debug_, "delay_calc", 3, " %s", + network_->pathName(drvr_pin)); + multi_drvr_net_map_[drvr] = multi_drvr; + drvr_vertices.push_back(drvr); + Level drvr_level = drvr->level(); + if (max_drvr == nullptr + || drvr_level > max_drvr_level) { + max_drvr = drvr; + max_drvr_level = drvr_level; + } + } + } } + multi_drvr->setDcalcDrvr(max_drvr); + multi_drvr->findCaps(sdc_); + return multi_drvr; } - multi_drvr->setDcalcDrvr(max_drvr); - multi_drvr->findCaps(sdc_); - return multi_drvr; + report_->critical(1101, "mult_drvr missing load."); + return nullptr; } void @@ -751,7 +783,7 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, && multi_drvr->parallelGates(network_)) { // Only init on the trigger driver. if (drvr_vertex == multi_drvr->dcalcDrvr()) { - for (auto vertex : *multi_drvr->drvrs()) + for (auto vertex : multi_drvr->drvrs()) initWireDelays(vertex); } } @@ -902,7 +934,7 @@ GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex, ArcDelayCalc *arc_delay_calc) { ArcDcalcArgSeq dcalc_args; - for (auto drvr_vertex1 : *multi_drvr->drvrs()) { + for (auto drvr_vertex1 : multi_drvr->drvrs()) { Edge *edge1 = nullptr; const TimingArc *arc1 = nullptr; if (drvr_vertex1 == drvr_vertex) { @@ -1526,17 +1558,11 @@ GraphDelayCalc::minPeriod(const Pin *pin, //////////////////////////////////////////////////////////////// -MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) : - dcalc_drvr_(nullptr), - drvrs_(drvrs) +MultiDrvrNet::MultiDrvrNet() : + dcalc_drvr_(nullptr) { } -MultiDrvrNet::~MultiDrvrNet() -{ - delete drvrs_; -} - void MultiDrvrNet::netCaps(const RiseFall *drvr_rf, const DcalcAnalysisPt *dcalc_ap, diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index b6ae00dc..ef467261 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -17,6 +17,7 @@ #pragma once #include +#include #include "Map.hh" #include "NetworkClass.hh" @@ -176,8 +177,11 @@ protected: const DcalcAnalysisPt *dcalc_ap); bool findDriverDelays(Vertex *drvr_vertex, ArcDelayCalc *arc_delay_calc); + MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; MultiDrvrNet *findMultiDrvrNet(Vertex *drvr_pin); - MultiDrvrNet *makeMultiDrvrNet(PinSet &drvr_pins); + MultiDrvrNet *makeMultiDrvrNet(Vertex *drvr_vertex); + bool hasMultiDrvrs(Vertex *drvr_vertex); + Vertex *firstLoad(Vertex *drvr_vertex); bool findDriverDelays1(Vertex *drvr_vertex, MultiDrvrNet *multi_drvr, ArcDelayCalc *arc_delay_calc); @@ -238,7 +242,6 @@ protected: const RiseFall *from_rf, const DcalcAnalysisPt *dcalc_ap); bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const; - MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; void loadCap(const Parasitic *parasitic, bool has_set_load, // Return values. @@ -263,7 +266,7 @@ protected: SearchPred *clk_pred_; BfsFwdIterator *iter_; MultiDrvrNetMap multi_drvr_net_map_; - bool multi_drvr_nets_found_; + std::mutex multi_drvr_lock_; // Percentage (0.0:1.0) change in delay that causes downstream // delays to be recomputed during incremental delay calculation. float incremental_delay_tolerance_; @@ -288,10 +291,9 @@ public: class MultiDrvrNet { public: - MultiDrvrNet(VertexSet *drvrs); - ~MultiDrvrNet(); - const VertexSet *drvrs() const { return drvrs_; } - VertexSet *drvrs() { return drvrs_; } + MultiDrvrNet(); + VertexSeq &drvrs() { return drvrs_; } + const VertexSeq &drvrs() const { return drvrs_; } bool parallelGates(const Network *network) const; Vertex *dcalcDrvr() const { return dcalc_drvr_; } void setDcalcDrvr(Vertex *drvr); @@ -307,7 +309,7 @@ public: private: // Driver that triggers delay calculation for all the drivers on the net. Vertex *dcalc_drvr_; - VertexSet *drvrs_; + VertexSeq drvrs_; // [drvr_rf->index][dcalc_ap->index] vector net_caps_; };