Skip to content

Commit 97b711c

Browse files
committed
report -unique_edges_to_endpoint
commit d8bb65d6e87cf95b3eada82b315351867b50fa01 Author: James Cherry <[email protected]> Date: Tue Nov 4 12:25:56 2025 -0700 report -unique_edges_to_endpoint doc Signed-off-by: James Cherry <[email protected]> commit 2979eda02f4f2fb38da4a5df9e9ece0d00951b6f Author: James Cherry <[email protected]> Date: Mon Nov 3 11:51:02 2025 -0700 redirect report_check_types Signed-off-by: James Cherry <[email protected]> commit 55960d4a63a999fc08f311c53fb053e4d54d1029 Author: James Cherry <[email protected]> Date: Mon Nov 3 11:28:15 2025 -0700 report -unique_edges_to_endpoint Signed-off-by: James Cherry <[email protected]> commit 8c56b5c2c08f546fee02e017a87cd94480dbabfc Author: James Cherry <[email protected]> Date: Sun Nov 2 16:05:28 2025 -0700 PathEnum cleanup Signed-off-by: James Cherry <[email protected]> commit c02b96a9c7b6e7c9ce99ee76a211f365bcda7428 Author: James Cherry <[email protected]> Date: Sun Nov 2 11:16:34 2025 -0700 PathEnum cleanup Signed-off-by: James Cherry <[email protected]> Signed-off-by: James Cherry <[email protected]>
1 parent f6523bd commit 97b711c

File tree

13 files changed

+1210
-1157
lines changed

13 files changed

+1210
-1157
lines changed

doc/ChangeLog.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ build directory instead of `app/`.
1212
The set_max_delay and set_min_delay commands now support the -probe option.
1313
With -probe these commands do not break paths at internal (non-startpoint) pins.
1414

15+
The report_checks command now supports a -unique_edges_to_endpoint option
16+
to remove paths through identical pins and rise/fall edges.
17+
18+
report_checks [-unique_edges_to_endpoint]
19+
1520
Release 2.6.1 2025/03/30
1621
-------------------------
1722

doc/OpenSTA.fodt

Lines changed: 1055 additions & 1034 deletions
Large diffs are not rendered by default.

doc/OpenSTA.pdf

-4.96 KB
Binary file not shown.

include/sta/PathGroup.hh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ public:
5353
int group_path_count,
5454
int endpoint_path_count,
5555
bool unique_pins,
56+
bool unique_edges,
5657
const MinMax *min_max,
5758
const StaState *sta);
5859
// Path group that compares arrival time, sorted by min_max.
5960
static PathGroup *makePathGroupSlack(const char *name,
6061
int group_path_count,
6162
int endpoint_path_count,
6263
bool unique_pins,
64+
bool unique_edges,
6365
float min_slack,
6466
float max_slack,
6567
const StaState *sta);
@@ -83,6 +85,7 @@ protected:
8385
size_t group_path_count,
8486
size_t endpoint_path_count,
8587
bool unique_pins,
88+
bool unique_edges,
8689
float min_slack,
8790
float max_slack,
8891
bool cmp_slack,
@@ -96,6 +99,7 @@ protected:
9699
size_t group_path_count_;
97100
size_t endpoint_path_count_;
98101
bool unique_pins_;
102+
bool unique_edges_;
99103
float slack_min_;
100104
float slack_max_;
101105
PathEndSeq path_ends_;
@@ -112,6 +116,7 @@ public:
112116
PathGroups(int group_path_count,
113117
int endpoint_path_count,
114118
bool unique_pins,
119+
bool unique_edges,
115120
float slack_min,
116121
float slack_max,
117122
PathGroupNameSet *group_names,
@@ -148,6 +153,7 @@ protected:
148153
int group_path_count,
149154
int endpoint_path_count,
150155
bool unique_pins,
156+
bool unique_edges,
151157
const Corner *corner,
152158
const MinMaxAll *min_max);
153159
void makeGroupPathEnds(ExceptionTo *to,
@@ -162,6 +168,7 @@ protected:
162168
int group_path_count,
163169
int endpoint_path_count,
164170
bool unique_pins,
171+
bool unique_edges,
165172
bool cmp_slack);
166173

167174
void pushGroupPathEnds(PathEndSeq &path_ends);
@@ -171,6 +178,7 @@ protected:
171178
void makeGroups(int group_path_count,
172179
int endpoint_path_count,
173180
bool unique_pins,
181+
bool unique_edges,
174182
float slack_min,
175183
float slack_max,
176184
PathGroupNameSet *group_names,
@@ -185,6 +193,7 @@ protected:
185193
int group_path_count_;
186194
int endpoint_path_count_;
187195
bool unique_pins_;
196+
bool unique_edges_;
188197
float slack_min_;
189198
float slack_max_;
190199

include/sta/Search.hh

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public:
105105
size_t group_path_count,
106106
size_t endpoint_path_count,
107107
bool unique_pins,
108+
bool unique_edges,
108109
float slack_min,
109110
float slack_max,
110111
bool sort_by_slack,
@@ -169,18 +170,6 @@ public:
169170

170171
PathGroupSeq pathGroups(const PathEnd *path_end) const;
171172
void deletePathGroups();
172-
void makePathGroups(int group_path_count,
173-
int endpoint_path_count,
174-
bool unique_pins,
175-
float min_slack,
176-
float max_slack,
177-
PathGroupNameSet *group_names,
178-
bool setup,
179-
bool hold,
180-
bool recovery,
181-
bool removal,
182-
bool clk_gating_setup,
183-
bool clk_gating_hold);
184173
virtual ExceptionPath *exceptionTo(ExceptionPathType type,
185174
const Path *path,
186175
const Pin *pin,

include/sta/Sta.hh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,9 +821,12 @@ public:
821821
// Number of paths to report for
822822
// each endpoint.
823823
int endpoint_path_count,
824-
// endpoint_path_count paths report unique pins
825-
// without rise/fall variations.
824+
// endpoint_path_count paths report paths with
825+
// unique pins.
826826
bool unique_pins,
827+
// endpoint_path_count paths report paths with
828+
// unique pins and rise/fall edges.
829+
bool unique_edges,
827830
// Min/max bounds for slack of
828831
// returned path ends.
829832
float slack_min,

search/PathEnum.cc

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace sta {
4848
// after_div<--------+
4949
// |
5050
// <--...--before_div<--...--path<---path_end
51+
//
5152
class Diversion
5253
{
5354
public:
@@ -105,13 +106,15 @@ deleteDiversionPathEnd(Diversion *div)
105106
PathEnum::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

232235
typedef std::set<std::pair<const Vertex*, const TimingArc*>> VisitedFanins;
236+
typedef std::pair<const Vertex*, const RiseFall*> VertexEdge;
233237

234238
class PathEnumFaninVisitor : public PathVisitor
235239
{
236240
public:
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

294302
PathEnumFaninVisitor::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+
313330
void
314331
PathEnumFaninVisitor::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-
376394
bool
377395
PathEnumFaninVisitor::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+
432457
void
433458
PathEnumFaninVisitor::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

451472
void
@@ -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
486500
void
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

Comments
 (0)