@@ -48,6 +48,7 @@ namespace sta {
4848// after_div<--------+
4949// |
5050// <--...--before_div<--...--path<---path_end
51+ //
5152class Diversion
5253{
5354public:
@@ -105,13 +106,15 @@ deleteDiversionPathEnd(Diversion *div)
105106PathEnum::PathEnum (size_t group_path_count,
106107 size_t endpoint_path_count,
107108 bool unique_pins,
109+ bool unique_edges,
108110 bool cmp_slack,
109111 const StaState *sta) :
110112 StaState (sta),
111113 cmp_slack_ (cmp_slack),
112114 group_path_count_ (group_path_count),
113115 endpoint_path_count_ (endpoint_path_count),
114116 unique_pins_ (unique_pins),
117+ unique_edges_ (unique_edges),
115118 div_queue_ (DiversionGreater(sta)),
116119 div_count_ (0 ),
117120 inserts_pruned_ (false ),
@@ -230,13 +233,15 @@ PathEnum::reportDiversionPath(Diversion *div)
230233// //////////////////////////////////////////////////////////////
231234
232235typedef std::set<std::pair<const Vertex*, const TimingArc*>> VisitedFanins;
236+ typedef std::pair<const Vertex*, const RiseFall*> VertexEdge;
233237
234238class PathEnumFaninVisitor : public PathVisitor
235239{
236240public:
237241 PathEnumFaninVisitor (PathEnd *path_end,
238242 Path *before_div,
239243 bool unique_pins,
244+ bool unique_edges,
240245 PathEnum *path_enum);
241246 virtual VertexVisitor *copy () const override ;
242247 void visitFaninPathsThru (Path *before_div,
@@ -271,13 +276,15 @@ class PathEnumFaninVisitor : public PathVisitor
271276 const Pin *to_pin,
272277 Vertex *to_vertex) override ;
273278 virtual void visit (Vertex *) override {} // Not used.
279+ void insertUniqueEdgeDiv (Diversion *div);
274280 void reportDiversion (const Edge *edge,
275281 const TimingArc *div_arc,
276282 Path *after_div);
277283
278284 PathEnd *path_end_;
279285 Path *before_div_;
280286 bool unique_pins_;
287+ bool unique_edges_;
281288 PathEnum *path_enum_;
282289
283290 Slack path_end_slack_;
@@ -289,16 +296,19 @@ class PathEnumFaninVisitor : public PathVisitor
289296 Vertex *prev_vertex_;
290297 bool crpr_active_;
291298 VisitedFanins visited_fanins_;
299+ std::map<VertexEdge, Diversion*> unique_edge_divs_;
292300};
293301
294302PathEnumFaninVisitor::PathEnumFaninVisitor (PathEnd *path_end,
295303 Path *before_div,
296304 bool unique_pins,
305+ bool unique_edges,
297306 PathEnum *path_enum) :
298307 PathVisitor (path_enum),
299308 path_end_ (path_end),
300309 before_div_ (before_div),
301310 unique_pins_ (unique_pins),
311+ unique_edges_ (unique_edges),
302312 path_enum_ (path_enum),
303313
304314 path_end_slack_ (path_end->slack (this )),
@@ -310,6 +320,13 @@ PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end,
310320{
311321}
312322
323+ VertexVisitor *
324+ PathEnumFaninVisitor::copy () const
325+ {
326+ return new PathEnumFaninVisitor (path_end_, before_div_, unique_pins_,
327+ unique_edges_, path_enum_);
328+ }
329+
313330void
314331PathEnumFaninVisitor::visitFaninPathsThru (Path *before_div,
315332 Vertex *prev_vertex,
@@ -324,7 +341,13 @@ PathEnumFaninVisitor::visitFaninPathsThru(Path *before_div,
324341 prev_arc_ = prev_arc;
325342 prev_vertex_ = prev_vertex;
326343 visited_fanins_.clear ();
344+ unique_edge_divs_.clear ();
327345 visitFaninPaths (before_div_->vertex (this ));
346+
347+ if (unique_edges_) {
348+ for (auto [vertex_edge, div] : unique_edge_divs_)
349+ path_enum_->insert (div);
350+ }
328351}
329352
330353// Specialize PathVisitor::visitEdge to filter paths/arcs to
@@ -342,13 +365,15 @@ PathEnumFaninVisitor::visitEdge(const Pin *from_pin,
342365 VertexPathIterator from_iter (from_vertex, search_);
343366 while (from_iter.hasNext ()) {
344367 Path *from_path = from_iter.next ();
368+ // Filter paths by path ap.
345369 PathAnalysisPt *path_ap = from_path->pathAnalysisPt (this );
346370 if (path_ap->index () == before_div_ap_index_) {
347371 const MinMax *min_max = path_ap->pathMinMax ();
348372 const RiseFall *from_rf = from_path->transition (this );
349373 TimingArc *arc1, *arc2;
350374 arc_set->arcsFrom (from_rf, arc1, arc2);
351- if (arc1 && arc1->toEdge ()->asRiseFall ()->index () == before_div_rf_index_) {
375+ // Filter arcs by to edge.
376+ if (arc1 && arc1->toEdge ()->asRiseFall ()->index () == before_div_rf_index_) {
352377 if (!visitArc (from_pin, from_vertex, from_rf, from_path,
353378 edge, arc1, to_pin, to_vertex,
354379 min_max, path_ap))
@@ -366,13 +391,6 @@ PathEnumFaninVisitor::visitEdge(const Pin *from_pin,
366391 return true ;
367392}
368393
369- VertexVisitor *
370- PathEnumFaninVisitor::copy () const
371- {
372- return new PathEnumFaninVisitor (path_end_, before_div_, unique_pins_,
373- path_enum_);
374- }
375-
376394bool
377395PathEnumFaninVisitor::visitFromToPath (const Pin *,
378396 Vertex *from_vertex,
@@ -393,42 +411,49 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
393411 // These paths fanin to before_div_ so we know to_vertex matches.
394412 if ((!unique_pins_ || from_vertex != prev_vertex_)
395413 && arc != prev_arc_
396- && Tag::matchNoCrpr (to_tag, before_div_tag_)) {
414+ && Tag::matchNoCrpr (to_tag, before_div_tag_)
415+ // Ignore paths that only differ by crpr from same vertex/edge.
416+ && (!crpr_active_
417+ || visited_fanins_.find ({from_vertex, arc}) == visited_fanins_.end ())) {
397418 debugPrint (debug_, " path_enum" , 3 , " visit fanin %s -> %s %s %s" ,
398419 from_path->to_string (this ).c_str (),
399420 to_vertex->to_string (this ).c_str (),
400421 to_rf->to_string ().c_str (),
401422 delayAsString (search_->deratedDelay (from_vertex, arc, edge,
402423 false ,path_ap), this ));
403- if (crpr_active_) {
404- // Ingore paths that only differ by crpr from same vertex/edge.
405- if (visited_fanins_.find ({from_vertex, arc}) == visited_fanins_.end ()) {
406- PathEnd *div_end;
407- Path *after_div_copy;
408- // Make the diverted path end to check slack with from_path crpr.
409- makeDivertedPathEnd (from_path, edge, arc, div_end, after_div_copy);
410- if (div_end) {
411- reportDiversion (edge, arc, from_path);
412- path_enum_->makeDiversion (div_end, after_div_copy);
413- visited_fanins_.emplace (from_vertex, arc);
414- }
415- }
416- else
417- debugPrint (debug_, " path_enum" , 3 , " pruned %s %s" ,
418- edge->to_string (this ).c_str (),
419- arc->to_string ().c_str ());
420- }
421- else {
422- PathEnd *div_end;
423- Path *after_div_copy;
424- makeDivertedPathEnd (from_path, edge, arc, div_end, after_div_copy);
425- reportDiversion (edge, arc, from_path);
426- path_enum_->makeDiversion (div_end, after_div_copy);
427- }
424+ PathEnd *div_end;
425+ Path *after_div_copy;
426+ // Make the diverted path end to check slack with from_path crpr.
427+ makeDivertedPathEnd (from_path, edge, arc, div_end, after_div_copy);
428+ reportDiversion (edge, arc, from_path);
429+ Diversion *div = new Diversion (div_end, after_div_copy);
430+ if (unique_edges_)
431+ insertUniqueEdgeDiv (div);
432+ else
433+ path_enum_->insert (div);
434+ if (crpr_active_)
435+ visited_fanins_.emplace (from_vertex, arc);
428436 }
437+ else
438+ debugPrint (debug_, " path_enum" , 3 , " pruned %s %s" ,
439+ edge->to_string (this ).c_str (),
440+ arc->to_string ().c_str ());
429441 return true ;
430442}
431443
444+ void
445+ PathEnumFaninVisitor::insertUniqueEdgeDiv (Diversion *div)
446+ {
447+ Slack div_slack = div->pathEnd ()->slack (this );
448+ const Path *div_path = div->divPath ();
449+ const Vertex *div_vertex = div_path->vertex (this );
450+ const RiseFall *div_rf = div_path->transition (this );
451+ auto itr = unique_edge_divs_.find ({div_vertex, div_rf});
452+ if (itr == unique_edge_divs_.end ()
453+ || div_slack > itr->second ->pathEnd ()->slack (this ))
454+ itr->second = div;
455+ }
456+
432457void
433458PathEnumFaninVisitor::makeDivertedPathEnd (Path *after_div,
434459 Edge *div_edge,
@@ -440,12 +465,8 @@ PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div,
440465 Path *div_path;
441466 path_enum_->makeDivertedPath (path_end_->path (), before_div_, after_div,
442467 div_edge, div_arc, div_path, after_div_copy);
443- if (after_div_copy) {
444- div_end = path_end_->copy ();
445- div_end->setPath (div_path);
446- }
447- else
448- div_end = nullptr ;
468+ div_end = path_end_->copy ();
469+ div_end->setPath (div_path);
449470}
450471
451472void
@@ -476,21 +497,11 @@ PathEnumFaninVisitor::reportDiversion(const Edge *div_edge,
476497 }
477498}
478499
479- // A diversion is an alternate path formed by changing the previous
480- // path/arc of before_div to after_div/div_arc in path.
481- //
482- // div_arc
483- // after_div<--------+
484- // |
485- // <--...--before_div<--...--path<---path_end
486500void
487- PathEnum::makeDiversion (PathEnd *div_end,
488- Path *after_div_copy)
501+ PathEnum::insert (Diversion *div)
489502{
490- Diversion *div = new Diversion (div_end, after_div_copy);
491503 div_queue_.push (div);
492504 div_count_++;
493-
494505 if (div_queue_.size () > group_path_count_ * 2 )
495506 // We have more potenial paths than we will need.
496507 pruneDiversionQueue ();
@@ -550,7 +561,7 @@ PathEnum::divSlack(Path *before_div,
550561 }
551562 }
552563 else {
553- report () ->error (1370 , " path diversion missing edge." );
564+ report_ ->error (1370 , " path diversion missing edge." );
554565 return 0.0 ;
555566 }
556567}
@@ -564,7 +575,8 @@ PathEnum::makeDiversions(PathEnd *path_end,
564575 Path *path = before;
565576 Path *prev_path = path->prevPath ();
566577 TimingArc *prev_arc = path->prevArc (this );
567- PathEnumFaninVisitor fanin_visitor (path_end, path, unique_pins_, this );
578+ PathEnumFaninVisitor fanin_visitor (path_end, path, unique_pins_,
579+ unique_edges_, this );
568580 while (prev_path) {
569581 // Fanin visitor does all the work.
570582 // While visiting the fanins the fanin_visitor finds the
0 commit comments