diff --git a/CMakeLists.txt b/CMakeLists.txt index d9b64958..530b3b0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,9 +189,10 @@ set(STA_SOURCE search/PathEnumed.cc search/PathExpanded.cc search/PathGroup.cc + search/PathPrev.cc search/PathRef.cc search/PathVertex.cc - search/PathVertexRep.cc + search/PathVertexPtr.cc search/Property.cc search/ReportPath.cc search/Search.cc diff --git a/graph/Graph.cc b/graph/Graph.cc index 12561a64..c0961f05 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -613,17 +613,17 @@ Graph::deleteRequireds(Vertex *vertex) vertex->setRequireds(nullptr); } -PathVertexRep * +PathPrev * Graph::prevPaths(const Vertex *vertex) const { return vertex->prevPaths(); } -PathVertexRep * +PathPrev * Graph::makePrevPaths(Vertex *vertex, uint32_t count) { - PathVertexRep *prev_paths = new PathVertexRep[count]; + PathPrev *prev_paths = new PathPrev[count]; vertex->setPrevPaths(prev_paths); return prev_paths; } @@ -1167,7 +1167,7 @@ Vertex::setRequireds(Required *requireds) } void -Vertex::setPrevPaths(PathVertexRep *prev_paths) +Vertex::setPrevPaths(PathPrev *prev_paths) { delete [] prev_paths_; prev_paths_ = prev_paths; diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 8cedd97e..4aa2313a 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -36,7 +36,7 @@ #include "Delay.hh" #include "GraphClass.hh" #include "VertexId.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" #include "StaState.hh" namespace sta { @@ -55,7 +55,7 @@ typedef ObjectId EdgeId; static constexpr EdgeId edge_id_null = object_id_null; static constexpr ObjectIdx edge_idx_null = object_id_null; -static constexpr ObjectIdx vertex_idx_null = object_id_null; +static constexpr ObjectIdx vertex_idx_null = object_idx_null; // The graph acts as a BUILDER for the graph vertices and edges. class Graph : public StaState @@ -104,9 +104,9 @@ public: uint32_t count); Required *requireds(const Vertex *vertex) const; void deleteRequireds(Vertex *vertex); - PathVertexRep *makePrevPaths(Vertex *vertex, + PathPrev *makePrevPaths(Vertex *vertex, uint32_t count); - PathVertexRep *prevPaths(const Vertex *vertex) const; + PathPrev *prevPaths(const Vertex *vertex) const; void deletePrevPaths(Vertex *vertex); // Private to Search::deletePaths(Vertex). void deletePaths(Vertex *vertex); @@ -271,8 +271,8 @@ public: const Slew *slews() const { return slews_; } Arrival *arrivals() const { return arrivals_; } Arrival *requireds() const { return requireds_; } - PathVertexRep *prevPaths() const { return prev_paths_; } - void setPrevPaths(PathVertexRep *prev_paths); + PathPrev *prevPaths() const { return prev_paths_; } + void setPrevPaths(PathPrev *prev_paths); TagGroupIndex tagGroupIndex() const; void setTagGroupIndex(TagGroupIndex tag_index); // Slew is annotated by sdc set_annotated_transition cmd. @@ -337,7 +337,7 @@ protected: // Search Arrival *arrivals_; Arrival *requireds_; - PathVertexRep *prev_paths_; + PathPrev *prev_paths_; // These fields are written by multiple threads, so they // cannot share the same word as the following bit fields. @@ -382,7 +382,9 @@ public: Edge(); ~Edge(); Vertex *to(const Graph *graph) const { return graph->vertex(to_); } + VertexId to() const { return to_; } Vertex *from(const Graph *graph) const { return graph->vertex(from_); } + VertexId from() const { return from_; } TimingRole *role() const; bool isWire() const; TimingSense sense() const; diff --git a/include/sta/PathPrev.hh b/include/sta/PathPrev.hh new file mode 100644 index 00000000..3643bef1 --- /dev/null +++ b/include/sta/PathPrev.hh @@ -0,0 +1,75 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include "SdcClass.hh" +#include "SearchClass.hh" + +namespace sta { + +// "Pointer" to a previous path on a vertex (PathVertex) thru an edge/arc. +class PathPrev +{ +public: + PathPrev(); + PathPrev(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta); + void init(); + void init(const PathPrev *path); + void init(const PathPrev &path); + void init(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta); + bool isNull() const; + const char *name(const StaState *sta) const; + Vertex *vertex(const StaState *sta) const; + VertexId vertexId(const StaState *sta) const; + Edge *prevEdge(const StaState *sta) const; + TimingArc *prevArc(const StaState *sta) const; + Tag *tag(const StaState *sta) const; + TagIndex tagIndex() const { return prev_tag_index_; } + Arrival arrival(const StaState *sta) const; + void prevPath(const StaState *sta, + // Return values. + PathRef &prev_path, + TimingArc *&prev_arc) const; + + static bool equal(const PathPrev *path1, + const PathPrev *path2); + static bool equal(const PathPrev &path1, + const PathPrev &path2); + static int cmp(const PathPrev &path1, + const PathPrev &path2); + +protected: + EdgeId prev_edge_id_; + TagIndex prev_tag_index_:tag_index_bit_count; + unsigned prev_arc_idx_:2; +}; + +} // namespace diff --git a/include/sta/PathRef.hh b/include/sta/PathRef.hh index cec7b89a..50288e28 100644 --- a/include/sta/PathRef.hh +++ b/include/sta/PathRef.hh @@ -49,6 +49,8 @@ public: void init(const PathRef *path); void init(const PathVertex &path); void init(const PathVertex *path); + void init(const PathPrev &path, + const StaState *sta); void init(Vertex *vertex, Tag *tag, int arrival_index); diff --git a/include/sta/PathVertex.hh b/include/sta/PathVertex.hh index d8726d24..9d21140f 100644 --- a/include/sta/PathVertex.hh +++ b/include/sta/PathVertex.hh @@ -29,7 +29,8 @@ namespace sta { -class PathVertexRep; +class PathPrev; +class PathVertexPtr; // Implements Path API for a vertex. class PathVertex : public Path @@ -38,9 +39,11 @@ public: PathVertex(); PathVertex(const PathVertex &path); PathVertex(const PathVertex *path); - PathVertex(const PathVertexRep *path, + PathVertex(const PathPrev *path, const StaState *sta); - PathVertex(const PathVertexRep &path, + PathVertex(const PathPrev &path, + const StaState *sta); + PathVertex(const PathVertexPtr &path, const StaState *sta); // If tag is not in the vertex tag group isNull() is true. PathVertex(Vertex *vertex, @@ -50,9 +53,11 @@ public: Tag *tag, int arrival_index); void init(); - void init(const PathVertexRep *path, + void init(const PathPrev *path, const StaState *sta); - void init(const PathVertexRep &path, + void init(const PathPrev &path, + const StaState *sta); + void init(const PathVertexPtr &path, const StaState *sta); void init(Vertex *vertex, Tag *tag, diff --git a/include/sta/PathVertexPtr.hh b/include/sta/PathVertexPtr.hh new file mode 100644 index 00000000..80c89649 --- /dev/null +++ b/include/sta/PathVertexPtr.hh @@ -0,0 +1,63 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include "SearchClass.hh" + +namespace sta { + +// "Pointer" to a vertex path because there is no real path object to point to. +class PathVertexPtr +{ +public: + PathVertexPtr(); + PathVertexPtr(const PathVertex *path, + const StaState *sta); + void init(); + void init(const PathVertexPtr *path); + void init(const PathVertexPtr &path); + void init(const PathVertex *path, + const StaState *sta); + bool isNull() const; + const char *name(const StaState *sta) const; + Vertex *vertex(const StaState *sta) const; + VertexId vertexId() const { return vertex_id_; } + Tag *tag(const StaState *sta) const; + TagIndex tagIndex() const { return tag_index_; } + Arrival arrival(const StaState *sta) const; + + static bool equal(const PathVertexPtr *path1, + const PathVertexPtr *path2); + static bool equal(const PathVertexPtr &path1, + const PathVertexPtr &path2); + static int cmp(const PathVertexPtr &path1, + const PathVertexPtr &path2); + +protected: + VertexId vertex_id_; + TagIndex tag_index_; +}; + +} // namespace diff --git a/include/sta/PathVertexRep.hh b/include/sta/PathVertexRep.hh index b31c4ce6..d6249426 100644 --- a/include/sta/PathVertexRep.hh +++ b/include/sta/PathVertexRep.hh @@ -29,34 +29,30 @@ namespace sta { -// Path representation that references a vertex arrival via a tag. -// This does not implement the Path API which uses virtual functions -// that would make it larger. +// "Pointer" to a previous path on a vertex (PathVertex) thru an edge/arc. class PathVertexRep { public: - explicit PathVertexRep(); - explicit PathVertexRep(const PathVertexRep *path); - PathVertexRep(const PathVertexRep &path); - explicit PathVertexRep(const PathVertex *path, - const StaState *sta); - explicit PathVertexRep(const PathVertex &path, - const StaState *sta); - explicit PathVertexRep(VertexId vertex_id, - TagIndex tag_index, - bool is_enum); + PathVertexRep(); + PathVertexRep(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta); void init(); void init(const PathVertexRep *path); void init(const PathVertexRep &path); void init(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, const StaState *sta); - void init(const PathVertex &path, - const StaState *sta); - bool isNull() const { return vertex_id_ == 0; } - Vertex *vertex(const StaState *) const; - VertexId vertexId() const { return vertex_id_; } + bool isNull() const; + const char *name(const StaState *sta) const; + Vertex *vertex(const StaState *sta) const; + VertexId vertexId(const StaState *sta) const; + Edge *prevEdge(const StaState *sta) const; + TimingArc *prevArc(const StaState *sta) const; Tag *tag(const StaState *sta) const; - TagIndex tagIndex() const { return tag_index_; } + TagIndex tagIndex() const { return prev_tag_index_; } Arrival arrival(const StaState *sta) const; void prevPath(const StaState *sta, // Return values. @@ -67,15 +63,13 @@ public: const PathVertexRep *path2); static bool equal(const PathVertexRep &path1, const PathVertexRep &path2); - static int cmp(const PathVertexRep *path1, - const PathVertexRep *path2); static int cmp(const PathVertexRep &path1, const PathVertexRep &path2); protected: - VertexId vertex_id_; - TagIndex tag_index_; - bool is_enum_:1; + EdgeId prev_edge_id_; + TagIndex prev_tag_index_:tag_index_bit_count; + unsigned prev_arc_idx_:2; }; } // namespace diff --git a/include/sta/Search.hh b/include/sta/Search.hh index efa08c19..d59e9fa5 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -117,7 +117,6 @@ public: void arrivalsInvalid(); // Invalidate vertex arrival time. void arrivalInvalid(Vertex *vertex); - void arrivalInvalidDelete(Vertex *vertex); void arrivalInvalid(const Pin *pin); // Invalidate all required times. void requiredsInvalid(); @@ -373,6 +372,7 @@ public: bool unconstrained, bool thru_latches); VertexSeq filteredEndpoints(); + bool alwaysSavePrevPaths() const { return always_save_prev_paths_; } protected: void init(StaState *sta); @@ -613,6 +613,7 @@ protected: std::mutex pending_latch_outputs_lock_; VertexSet *endpoints_; VertexSet *invalid_endpoints_; + bool always_save_prev_paths_; // Filter exception to tag arrivals for // report_timing -from pin|inst -through. // -to is always nullptr. @@ -760,6 +761,7 @@ protected: void constrainedRequiredsInvalid(Vertex *vertex, bool is_clk); bool always_to_endpoints_; + bool always_save_prev_paths_; TagGroupBldr *tag_bldr_; TagGroupBldr *tag_bldr_no_crpr_; SearchPred *adj_pred_; diff --git a/include/sta/SearchClass.hh b/include/sta/SearchClass.hh index fb207de5..ac558426 100644 --- a/include/sta/SearchClass.hh +++ b/include/sta/SearchClass.hh @@ -43,7 +43,8 @@ class Corner; class Path; class PathRep; class PathVertex; -class PathVertexRep; +class PathPrev; +class PathVertexPtr; class PathRef; class PathEnumed; class PathEnd; @@ -136,7 +137,8 @@ enum class ReportPathFormat { full, json }; -static const TagIndex tag_index_max = std::numeric_limits::max(); +static const TagIndex tag_index_bit_count = 28; +static const TagIndex tag_index_max = (1 << tag_index_bit_count) - 1; static const TagIndex tag_index_null = tag_index_max; static const int path_ap_index_bit_count = 8; // One path analysis point per corner min/max. diff --git a/search/ClkInfo.cc b/search/ClkInfo.cc index 6aca9648..ca7559e9 100644 --- a/search/ClkInfo.cc +++ b/search/ClkInfo.cc @@ -53,7 +53,7 @@ ClkInfo::ClkInfo(const ClockEdge *clk_edge, float latency, ClockUncertainties *uncertainties, PathAPIndex path_ap_index, - PathVertexRep &crpr_clk_path, + PathVertexPtr &crpr_clk_path, const StaState *sta) : clk_edge_(clk_edge), clk_src_(clk_src), @@ -213,7 +213,7 @@ clkInfoEqual(const ClkInfo *clk_info1, && clk_info1->clkSrc() == clk_info2->clkSrc() && clk_info1->genClkSrc() == clk_info2->genClkSrc() && (!crpr_on - || (PathVertexRep::equal(clk_info1->crprClkPath(), + || (PathVertexPtr::equal(clk_info1->crprClkPath(), clk_info2->crprClkPath()))) && ((uncertainties1 == nullptr && uncertainties2 == nullptr) @@ -279,9 +279,9 @@ clkInfoCmp(const ClkInfo *clk_info1, bool crpr_on = sta->sdc()->crprActive(); if (crpr_on) { - const PathVertexRep &crpr_path1 = clk_info1->crprClkPath(); - const PathVertexRep &crpr_path2 = clk_info2->crprClkPath(); - int path_cmp = PathVertexRep::cmp(crpr_path1, crpr_path2); + const PathVertexPtr &crpr_path1 = clk_info1->crprClkPath(); + const PathVertexPtr &crpr_path2 = clk_info2->crprClkPath(); + int path_cmp = PathVertexPtr::cmp(crpr_path1, crpr_path2); if (path_cmp != 0) return path_cmp; } diff --git a/search/ClkInfo.hh b/search/ClkInfo.hh index 977f77d6..e7a548fd 100644 --- a/search/ClkInfo.hh +++ b/search/ClkInfo.hh @@ -26,7 +26,8 @@ #include "Transition.hh" #include "SearchClass.hh" -#include "PathVertexRep.hh" +#include "PathVertexPtr.hh" +#include "Sdc.hh" namespace sta { @@ -45,7 +46,7 @@ public: float latency, ClockUncertainties *uncertainties, PathAPIndex path_ap_index, - PathVertexRep &crpr_clk_path, + PathVertexPtr &crpr_clk_path, const StaState *sta); ~ClkInfo(); const char *asString(const StaState *sta) const; @@ -64,8 +65,8 @@ public: PathAPIndex pathAPIndex() const { return path_ap_index_; } // Clock path used for crpr resolution. // Null for clocks because the path cannot point to itself. - PathVertexRep &crprClkPath() { return crpr_clk_path_; } - const PathVertexRep &crprClkPath() const { return crpr_clk_path_; } + PathVertexPtr &crprClkPath() { return crpr_clk_path_; } + const PathVertexPtr &crprClkPath() const { return crpr_clk_path_; } VertexId crprClkVertexId() const; bool hasCrprClkPin() const { return !crpr_clk_path_.isNull(); } bool refsFilter(const StaState *sta) const; @@ -80,7 +81,7 @@ private: const ClockEdge *clk_edge_; const Pin *clk_src_; const Pin *gen_clk_src_; - PathVertexRep crpr_clk_path_; + PathVertexPtr crpr_clk_path_; ClockUncertainties *uncertainties_; Arrival insertion_; float latency_; diff --git a/search/Crpr.cc b/search/Crpr.cc index c692e731..ef35c772 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -33,7 +33,7 @@ #include "Graph.hh" #include "Sdc.hh" #include "PathVertex.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" #include "Path.hh" #include "PathAnalysisPt.hh" #include "ClkInfo.hh" @@ -63,7 +63,7 @@ CheckCrpr::clkPathPrev(const PathVertex *path, int arrival_index; bool exists; path->arrivalIndex(arrival_index, exists); - PathVertexRep *prevs = graph_->prevPaths(vertex); + PathPrev *prevs = graph_->prevPaths(vertex); if (prevs) prev.init(prevs[arrival_index], this); else @@ -74,7 +74,7 @@ PathVertex CheckCrpr::clkPathPrev(Vertex *vertex, int arrival_index) { - PathVertexRep *prevs = graph_->prevPaths(vertex); + PathPrev *prevs = graph_->prevPaths(vertex); if (prevs) return PathVertex(prevs[arrival_index], this); else { @@ -90,7 +90,7 @@ CheckCrpr::clkPathPrev(Vertex *vertex, Arrival CheckCrpr::maxCrpr(ClkInfo *clk_info) { - const PathVertexRep &crpr_clk_path = clk_info->crprClkPath(); + const PathVertexPtr &crpr_clk_path = clk_info->crprClkPath(); if (!crpr_clk_path.isNull()) { PathVertex crpr_clk_vpath(crpr_clk_path, this); if (!crpr_clk_vpath.isNull()) { @@ -166,7 +166,7 @@ CheckCrpr::checkCrpr1(const Path *src_path, const Clock *src_clk = src_clk_info->clock(); const Clock *tgt_clk = tgt_clk_info->clock(); PathVertex src_clk_path1; - PathVertexRep &src_crpr_clk_path = src_clk_info->crprClkPath(); + const PathVertexPtr &src_crpr_clk_path = src_clk_info->crprClkPath(); const PathVertex *src_clk_path = nullptr; if (src_tag->isClock()) { src_clk_path1.init(src_path->vertex(this), src_path->tag(this), this); diff --git a/search/Genclks.cc b/search/Genclks.cc index d76f0e80..573dcf0f 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -40,7 +40,7 @@ #include "Corner.hh" #include "PathAnalysisPt.hh" #include "Levelize.hh" -#include "PathVertexRep.hh" +#include "PathVertexPtr.hh" #include "Search.hh" namespace sta { @@ -856,7 +856,7 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex, { Arrival *arrivals = graph_->arrivals(vertex); if (arrivals) { - PathVertexRep *prev_paths = graph_->prevPaths(vertex); + PathPrev *prev_paths = graph_->prevPaths(vertex); TagGroup *tag_group = search_->tagGroup(vertex); if (tag_group) { ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap()); @@ -866,7 +866,7 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex, arrival_iter.next(tag, arrival_index); if (tag->isGenClkSrcPath()) { Arrival arrival = arrivals[arrival_index]; - PathVertexRep *prev_path = prev_paths + PathPrev *prev_path = prev_paths ? &prev_paths[arrival_index] : nullptr; tag_bldr->setArrival(tag, arrival, prev_path); @@ -903,7 +903,7 @@ Genclks::recordSrcPaths(Clock *gclk) bool has_edges = gclk->edges() != nullptr; for (const Pin *gclk_pin : gclk->leafPins()) { - PathVertexRep *src_paths = new PathVertexRep[path_count]; + PathVertexPtr *src_paths = new PathVertexPtr[path_count]; genclk_src_paths_.insert(ClockPinPair(gclk, gclk_pin), src_paths); Vertex *gclk_vertex = srcPathVertex(gclk_pin); @@ -920,7 +920,7 @@ Genclks::recordSrcPaths(Clock *gclk) bool inverting_path = (rf != src_clk_rf); const PathAnalysisPt *path_ap = path->pathAnalysisPt(this); int path_index = srcPathIndex(rf, path_ap); - PathVertexRep &src_path = src_paths[path_index]; + PathVertexPtr &src_path = src_paths[path_index]; if ((!divide_by_1 || (inverting_path == invert)) && (!has_edges @@ -999,7 +999,7 @@ Genclks::srcPath(const Clock *gclk, const RiseFall *rf, const PathAnalysisPt *path_ap) const { - PathVertexRep *src_paths = + PathVertexPtr *src_paths = genclk_src_paths_.findKey(ClockPinPair(gclk, src_pin)); if (src_paths) { int path_index = srcPathIndex(rf, path_ap); diff --git a/search/Genclks.hh b/search/Genclks.hh index 1d8189c4..7d662e1b 100644 --- a/search/Genclks.hh +++ b/search/Genclks.hh @@ -50,7 +50,7 @@ public: }; typedef Map GenclkInfoMap; -typedef Map GenclkSrcPathMap; +typedef Map GenclkSrcPathMap; class Genclks : public StaState { diff --git a/search/PathEnum.cc b/search/PathEnum.cc index 0b151b07..a8dd572c 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -354,13 +354,15 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *, PathEnumed *after_div_copy; // Make the diverted path end to check slack with from_path crpr. makeDivertedPathEnd(from_path, arc, div_end, after_div_copy); - // Only enumerate paths with greater slack. - if (delayGreaterEqual(div_end->slack(this), path_end_slack_, this)) { - reportDiversion(arc, from_path); - path_enum_->makeDiversion(div_end, after_div_copy); + if (div_end) { + // Only enumerate paths with greater slack. + if (delayGreaterEqual(div_end->slack(this), path_end_slack_, this)) { + reportDiversion(arc, from_path); + path_enum_->makeDiversion(div_end, after_div_copy); + } + else + delete div_end; } - else - delete div_end; } // Only enumerate slower/faster paths. else if (delayLessEqual(to_arrival, before_div_arrival_, min_max, this)) { @@ -384,8 +386,12 @@ PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div, PathEnumed *div_path; path_enum_->makeDivertedPath(path_end_->path(), &before_div_, after_div, div_arc, div_path, after_div_copy); - div_end = path_end_->copy(); - div_end->setPath(div_path); + if (after_div_copy) { + div_end = path_end_->copy(); + div_end->setPath(div_path); + } + else + div_end = nullptr; } void @@ -539,17 +545,15 @@ PathEnum::makeDivertedPath(Path *path, PathEnumed *&div_path, PathEnumed *&after_div_copy) { + div_path = nullptr; + after_div_copy = nullptr; // Copy the diversion path. bool found_div = false; PathEnumedSeq copies; PathRef p(path); bool first = true; PathEnumed *prev_copy = nullptr; - VertexSet visited(graph_); - while (!p.isNull() - // Break latch loops. - && !visited.hasKey(p.vertex(this))) { - visited.insert(p.vertex(this)); + while (!p.isNull()) { PathRef prev; TimingArc *prev_arc; p.prevPath(this, prev, prev_arc); @@ -562,10 +566,12 @@ PathEnum::makeDivertedPath(Path *path, prev_copy->setPrevPath(copy); copies.push_back(copy); - if (first) - div_path = copy; if (Path::equal(&p, after_div, this)) after_div_copy = copy; + if (first) + div_path = copy; + else if (network_->isLatchData(p.pin(this))) + break; if (Path::equal(&p, before_div, this)) { copy->setPrevArc(div_arc); // Update the delays forward from before_div to the end of the path. @@ -598,7 +604,7 @@ PathEnum::updatePathHeadDelays(PathEnumedSeq &paths, ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_), arc, edge, false, path_ap); Arrival arrival = prev_arrival + arc_delay; - debugPrint(debug_, "path_enum", 3, "update arrival %s %s %s -> %s", + debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s", path->vertex(this)->name(network_), path->tag(this)->asString(this), delayAsString(path->arrival(this), this), diff --git a/search/PathPrev.cc b/search/PathPrev.cc new file mode 100644 index 00000000..8de8d78a --- /dev/null +++ b/search/PathPrev.cc @@ -0,0 +1,246 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "PathPrev.hh" + +#include "Graph.hh" +#include "TimingArc.hh" +#include "SearchClass.hh" +#include "Tag.hh" +#include "TagGroup.hh" +#include "Search.hh" +#include "PathAnalysisPt.hh" +#include "PathVertex.hh" + +namespace sta { + +PathPrev::PathPrev() +{ + init(); +} + +void +PathPrev::init() +{ + prev_edge_id_ = edge_id_null; + prev_arc_idx_ = 0; + prev_tag_index_ = tag_index_null; +} + +void +PathPrev::init(const PathPrev *path) +{ + if (path) { + prev_edge_id_ = path->prev_edge_id_; + prev_arc_idx_ = path->prev_arc_idx_; + prev_tag_index_ = path->prev_tag_index_; + } + else + init(); +} + +void +PathPrev::init(const PathPrev &path) +{ + prev_edge_id_ = path.prev_edge_id_; + prev_arc_idx_ = path.prev_arc_idx_; + prev_tag_index_ = path.prev_tag_index_; +} + +void +PathPrev::init(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta) +{ + if (path == nullptr || path->isNull()) + init(); + else { + const Graph *graph = sta->graph(); + prev_edge_id_ = graph->id(prev_edge); + prev_arc_idx_ = prev_arc->index(); + prev_tag_index_ = path->tag(sta)->index(); + } +} + +const char * +PathPrev::name(const StaState *sta) const +{ + const Network *network = sta->network(); + const Search *search = sta->search(); + Vertex *vertex = this->vertex(sta); + if (vertex) { + const char *vertex_name = vertex->name(network); + const Tag *tag = this->tag(search); + const RiseFall *rf = tag->transition(); + const char *rf_str = rf->asString(); + const PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta); + int ap_index = path_ap->index(); + const char *min_max = path_ap->pathMinMax()->asString(); + TagIndex tag_index = tag->index(); + return stringPrintTmp("%s %s %s/%d %d", + vertex_name, rf_str, min_max, + ap_index, tag_index); + } + else + return "NULL"; +} + +bool +PathPrev::isNull() const +{ + return prev_edge_id_ == edge_id_null; +} + +VertexId +PathPrev::vertexId(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return vertex_id_null; + else { + const Graph *graph = sta->graph(); + const Edge *edge = graph->edge(prev_edge_id_); + return edge->from(); + } +} + +Vertex * +PathPrev::vertex(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + const Edge *edge = graph->edge(prev_edge_id_); + return edge->from(graph); + } +} + +Edge * +PathPrev::prevEdge(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + return graph->edge(prev_edge_id_); + } +} + +TimingArc * +PathPrev::prevArc(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + const Edge *edge = graph->edge(prev_edge_id_); + TimingArcSet *arc_set = edge->timingArcSet(); + return arc_set->findTimingArc(prev_arc_idx_); + } +} + +Tag * +PathPrev::tag(const StaState *sta) const +{ + const Search *search = sta->search(); + return search->tag(prev_tag_index_); +} + +Arrival +PathPrev::arrival(const StaState *sta) const +{ + Graph *graph = sta->graph(); + const Search *search = sta->search(); + Tag *tag = search->tag(prev_tag_index_); + Vertex *vertex = this->vertex(sta); + TagGroup *tag_group = search->tagGroup(vertex); + if (tag_group) { + int arrival_index; + bool arrival_exists; + tag_group->arrivalIndex(tag, arrival_index, arrival_exists); + if (!arrival_exists) + sta->report()->critical(1420, "tag group missing tag"); + Arrival *arrivals = graph->arrivals(vertex); + if (arrivals) + return arrivals[arrival_index]; + else + sta->report()->critical(1421, "missing arrivals"); + } + else + sta->report()->error(1422, "missing arrivals."); + return 0.0; +} + +void +PathPrev::prevPath(const StaState *sta, + // Return values. + PathRef &prev_path, + TimingArc *&prev_arc) const +{ + PathVertex path_vertex(this, sta); + path_vertex.prevPath(sta, prev_path, prev_arc); +} + +//////////////////////////////////////////////////////////////// + +bool +PathPrev::equal(const PathPrev *path1, + const PathPrev *path2) +{ + return path1->prev_edge_id_ == path2->prev_edge_id_ + && path1->prev_tag_index_ == path2->prev_tag_index_; +} + +bool +PathPrev::equal(const PathPrev &path1, + const PathPrev &path2) +{ + return path1.prev_edge_id_ == path2.prev_edge_id_ + && path1.prev_tag_index_ == path2.prev_tag_index_; +} + +int +PathPrev::cmp(const PathPrev &path1, + const PathPrev &path2) +{ + EdgeId edge_id1 = path1.prev_edge_id_; + EdgeId edge_id2 = path2.prev_edge_id_; + if (edge_id1 == edge_id2) { + TagIndex tag_index1 = path1.prev_tag_index_; + TagIndex tag_index2 = path2.prev_tag_index_; + if (tag_index1 == tag_index2) + return 0; + else if (tag_index1 < tag_index2) + return -1; + else + return 1; + } + else if (edge_id1 < edge_id2) + return -1; + else + return 1; +} + +} // namespace diff --git a/search/PathRef.cc b/search/PathRef.cc index 70401ef6..74bb0aae 100644 --- a/search/PathRef.cc +++ b/search/PathRef.cc @@ -96,6 +96,26 @@ PathRef::init(const PathVertex &path) path_vertex_ = path; } +void +PathRef::init(const PathPrev &path, + const StaState *sta) +{ + int arrival_index = 0; + TagIndex tag_index = path.tagIndex(); + Tag *tag = nullptr; + if (tag_index != tag_index_null) { + const Search *search = sta->search(); + tag = search->tag(tag_index); + Vertex *vertex = path.vertex(sta); + TagGroup *tag_group = search->tagGroup(vertex); + if (tag_group) { + bool arrival_exists; + tag_group->arrivalIndex(tag, arrival_index, arrival_exists); + } + } + path_vertex_.init(path.vertex(sta), tag, arrival_index); +} + void PathRef::init(Vertex *vertex, Tag *tag, diff --git a/search/PathVertex.cc b/search/PathVertex.cc index 5bb20a57..9efcc03e 100644 --- a/search/PathVertex.cc +++ b/search/PathVertex.cc @@ -36,7 +36,8 @@ #include "TagGroup.hh" #include "PathAnalysisPt.hh" #include "PathRef.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" +#include "PathVertexPtr.hh" #include "Search.hh" namespace sta { @@ -83,7 +84,7 @@ PathVertex::PathVertex(Vertex *vertex, { } -PathVertex::PathVertex(const PathVertexRep *path, +PathVertex::PathVertex(const PathPrev *path, const StaState *sta) { if (path) @@ -92,7 +93,16 @@ PathVertex::PathVertex(const PathVertexRep *path, init(); } -PathVertex::PathVertex(const PathVertexRep &path, +PathVertex::PathVertex(const PathPrev &path, + const StaState *sta) +{ + if (path.isNull()) + init(); + else + init(path.vertex(sta), path.tag(sta), sta); +} + +PathVertex::PathVertex(const PathVertexPtr &path, const StaState *sta) { if (path.isNull()) @@ -140,7 +150,7 @@ PathVertex::init(Vertex *vertex, } void -PathVertex::init(const PathVertexRep *path, +PathVertex::init(const PathPrev *path, const StaState *sta) { if (path) @@ -150,7 +160,17 @@ PathVertex::init(const PathVertexRep *path, } void -PathVertex::init(const PathVertexRep &path, +PathVertex::init(const PathPrev &path, + const StaState *sta) +{ + if (!path.isNull()) + init(path.vertex(sta), path.tag(sta), sta); + else + init(); +} + +void +PathVertex::init(const PathVertexPtr &path, const StaState *sta) { if (!path.isNull()) @@ -481,9 +501,19 @@ PathVertex::prevPath(const StaState *sta, PathRef &prev_path, TimingArc *&prev_arc) const { - PathVertex prev; - prevPath(sta, prev, prev_arc); - prev.setRef(prev_path); + const Graph *graph = sta->graph(); + Vertex *vertex = this->vertex(graph); + PathPrev *prev_paths = vertex->prevPaths(); + if (prev_paths) { + PathPrev &prev = prev_paths[arrival_index_]; + prev_path.init(prev, sta); + prev_arc = prev.isNull() ? nullptr : prev.prevArc(sta); + } + else { + PathVertex prev; + prevPath(sta, prev, prev_arc); + prev.setRef(prev_path); + } } //////////////////////////////////////////////////////////////// diff --git a/search/PathVertexPtr.cc b/search/PathVertexPtr.cc new file mode 100644 index 00000000..16fc7d9d --- /dev/null +++ b/search/PathVertexPtr.cc @@ -0,0 +1,201 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "PathVertexPtr.hh" + +#include "Graph.hh" +#include "TimingArc.hh" +#include "SearchClass.hh" +#include "Tag.hh" +#include "TagGroup.hh" +#include "Search.hh" +#include "PathAnalysisPt.hh" +#include "PathVertex.hh" + +namespace sta { + +PathVertexPtr::PathVertexPtr() : + vertex_id_(vertex_id_null), + tag_index_(tag_index_null) +{ +} + +PathVertexPtr::PathVertexPtr(const PathVertex *path, + const StaState *sta) +{ + init(path, sta); +} + +void +PathVertexPtr::init() +{ + vertex_id_ = vertex_id_null; + tag_index_ = tag_index_null; +} + +void +PathVertexPtr::init(const PathVertexPtr *path) +{ + if (path) { + vertex_id_ = path->vertex_id_; + tag_index_ = path->tag_index_; + } + else { + vertex_id_ = vertex_id_null; + tag_index_ = tag_index_null; + } +} + +void +PathVertexPtr::init(const PathVertexPtr &path) +{ + vertex_id_ = path.vertex_id_; + tag_index_ = path.tag_index_; +} + +void +PathVertexPtr::init(const PathVertex *path, + const StaState *sta) +{ + if (path == nullptr || path->isNull()) + init(); + else { + vertex_id_ = path->vertexId(sta); + tag_index_ = path->tagIndex(sta); + } +} + +const char * +PathVertexPtr::name(const StaState *sta) const +{ + const Network *network = sta->network(); + const Search *search = sta->search(); + Vertex *vertex = this->vertex(sta); + if (vertex) { + const char *vertex_name = vertex->name(network); + const Tag *tag = this->tag(search); + const RiseFall *rf = tag->transition(); + const char *rf_str = rf->asString(); + const PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta); + int ap_index = path_ap->index(); + const char *min_max = path_ap->pathMinMax()->asString(); + TagIndex tag_index = tag->index(); + return stringPrintTmp("%s %s %s/%d %d", + vertex_name, rf_str, min_max, + ap_index, tag_index); + } + else + return "NULL"; +} + +bool +PathVertexPtr::isNull() const +{ + return vertex_id_ == vertex_id_null; +} + +Vertex * +PathVertexPtr::vertex(const StaState *sta) const +{ + if (vertex_id_ == vertex_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + return graph->vertex(vertex_id_); + } +} + +Tag * +PathVertexPtr::tag(const StaState *sta) const +{ + const Search *search = sta->search(); + return search->tag(tag_index_); +} + +Arrival +PathVertexPtr::arrival(const StaState *sta) const +{ + const Vertex *vertex = this->vertex(sta); + Arrival *arrivals = sta->graph()->arrivals(vertex); + if (arrivals) { + const Search *search = sta->search(); + TagGroup *tag_group = search->tagGroup(vertex); + Tag *tag = this->tag(sta); + int arrival_index; + bool arrival_exists; + tag_group->arrivalIndex(tag, arrival_index, arrival_exists); + if (arrival_exists) + return arrivals[arrival_index]; + else { + sta->report()->error(1403, "missing arrival."); + return 0.0; + } + } + else { + sta->report()->error(1404, "missing arrivals."); + return 0.0; + } +} + +//////////////////////////////////////////////////////////////// + +bool +PathVertexPtr::equal(const PathVertexPtr *path1, + const PathVertexPtr *path2) +{ + return path1->vertex_id_ == path2->vertex_id_ + && path1->tag_index_ == path2->tag_index_; +} + +bool +PathVertexPtr::equal(const PathVertexPtr &path1, + const PathVertexPtr &path2) +{ + return path1.vertex_id_ == path2.vertex_id_ + && path1.tag_index_ == path2.tag_index_; +} + +int +PathVertexPtr::cmp(const PathVertexPtr &path1, + const PathVertexPtr &path2) +{ + VertexId vertex_id1 = path1.vertex_id_; + VertexId vertex_id2 = path2.vertex_id_; + if (vertex_id1 == vertex_id2) { + TagIndex tag_index1 = path1.tagIndex(); + TagIndex tag_index2 = path2.tagIndex(); + if (tag_index1 == tag_index2) + return 0; + else if (tag_index1 < tag_index2) + return -1; + else + return 1; + } + else if (vertex_id1 < vertex_id2) + return -1; + else + return 1; +} + +} // namespace diff --git a/search/PathVertexRep.cc b/search/PathVertexRep.cc deleted file mode 100644 index ebb3cd53..00000000 --- a/search/PathVertexRep.cc +++ /dev/null @@ -1,246 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2025, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#include "PathVertexRep.hh" - -#include "Graph.hh" -#include "SearchClass.hh" -#include "Tag.hh" -#include "TagGroup.hh" -#include "Search.hh" -#include "PathVertex.hh" - -namespace sta { - -PathVertexRep::PathVertexRep() -{ - init(); -} - -PathVertexRep::PathVertexRep(const PathVertexRep *path) -{ - init(path); -} - -PathVertexRep::PathVertexRep(const PathVertexRep &path) -{ - init(path); -} - -PathVertexRep::PathVertexRep(const PathVertex *path, - const StaState *sta) -{ - init(path, sta); -} - -PathVertexRep::PathVertexRep(const PathVertex &path, - const StaState *sta) -{ - init(path, sta); -} - -PathVertexRep::PathVertexRep(VertexId vertex_id, - TagIndex tag_index, - bool is_enum) : - vertex_id_(vertex_id), - tag_index_(tag_index), - is_enum_(is_enum) -{ -} - -void -PathVertexRep::init() -{ - vertex_id_ = 0; - tag_index_ = tag_index_null; - is_enum_ = false; -} - -void -PathVertexRep::init(const PathVertexRep *path) -{ - if (path) { - vertex_id_ = path->vertex_id_; - tag_index_ = path->tag_index_; - is_enum_ = false; - } - else - init(); -} - -void -PathVertexRep::init(const PathVertexRep &path) -{ - vertex_id_ = path.vertex_id_; - tag_index_ = path.tag_index_; - is_enum_ = false; -} - -void -PathVertexRep::init(const PathVertex *path, - const StaState *sta) -{ - if (path == nullptr || path->isNull()) - init(); - else { - vertex_id_ = sta->graph()->id(path->vertex(sta)); - tag_index_ = path->tag(sta)->index(); - is_enum_ = false; - } -} - -void -PathVertexRep::init(const PathVertex &path, - const StaState *sta) -{ - if (path.isNull()) - init(); - else { - vertex_id_ = sta->graph()->id(path.vertex(sta)); - tag_index_ = path.tag(sta)->index(); - is_enum_ = false; - } -} - -Vertex * -PathVertexRep::vertex(const StaState *sta) const -{ - const Graph *graph = sta->graph(); - return graph->vertex(vertex_id_); -} - -Tag * -PathVertexRep::tag(const StaState *sta) const -{ - const Search *search = sta->search(); - return search->tag(tag_index_); -} - -Arrival -PathVertexRep::arrival(const StaState *sta) const -{ - Graph *graph = sta->graph(); - const Search *search = sta->search(); - Tag *tag = search->tag(tag_index_); - Vertex *vertex = graph->vertex(vertex_id_); - TagGroup *tag_group = search->tagGroup(vertex); - if (tag_group) { - int arrival_index; - bool arrival_exists; - tag_group->arrivalIndex(tag, arrival_index, arrival_exists); - if (!arrival_exists) - sta->report()->critical(1420, "tag group missing tag"); - Arrival *arrivals = graph->arrivals(vertex); - if (arrivals) - return arrivals[arrival_index]; - else - sta->report()->critical(1421, "missing arrivals"); - } - else - sta->report()->error(1422, "missing arrivals."); - return 0.0; -} - -void -PathVertexRep::prevPath(const StaState *sta, - // Return values. - PathRef &prev_path, - TimingArc *&prev_arc) const -{ - PathVertex path_vertex(this, sta); - path_vertex.prevPath(sta, prev_path, prev_arc); -} - -//////////////////////////////////////////////////////////////// - -bool -PathVertexRep::equal(const PathVertexRep *path1, - const PathVertexRep *path2) -{ - return path1->vertex_id_ == path2->vertex_id_ - && path1->tag_index_ == path2->tag_index_; -} - -bool -PathVertexRep::equal(const PathVertexRep &path1, - const PathVertexRep &path2) -{ - return path1.vertex_id_ == path2.vertex_id_ - && path1.tag_index_ == path2.tag_index_; -} - -int -PathVertexRep::cmp(const PathVertexRep *path1, - const PathVertexRep *path2) -{ - if (path1 && path2) { - VertexId vertex_id1 = path1->vertexId(); - VertexId vertex_id2 = path2->vertexId(); - if (vertex_id1 == vertex_id2) { - TagIndex tag_index1 = path1->tagIndex(); - TagIndex tag_index2 = path2->tagIndex(); - if (tag_index1 == tag_index2) - return 0; - else if (tag_index1 < tag_index2) - return -1; - else - return 1; - } - else if (vertex_id1 < vertex_id2) - return -1; - else - return 1; - } - else if (path1 == nullptr - && path2 == nullptr) - return 0; - else if (path1 == nullptr) - return -1; - else - return 1; -} - -int -PathVertexRep::cmp(const PathVertexRep &path1, - const PathVertexRep &path2) -{ - VertexId vertex_id1 = path1.vertexId(); - VertexId vertex_id2 = path2.vertexId(); - if (vertex_id1 == vertex_id2) { - TagIndex tag_index1 = path1.tagIndex(); - TagIndex tag_index2 = path2.tagIndex(); - if (tag_index1 == tag_index2) - return 0; - else if (tag_index1 < tag_index2) - return -1; - else - return 1; - } - else if (vertex_id1 < vertex_id2) - return -1; - else - return 1; -} - -} // namespace diff --git a/search/Search.cc b/search/Search.cc index 64bed38b..97acec66 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -55,7 +55,7 @@ #include "Corner.hh" #include "Sim.hh" #include "PathVertex.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" #include "PathRef.hh" #include "ClkInfo.hh" #include "Tag.hh" @@ -255,6 +255,7 @@ Search::init(StaState *sta) path_groups_ = nullptr; endpoints_ = nullptr; invalid_endpoints_ = nullptr; + always_save_prev_paths_ = true; filter_ = nullptr; filter_from_ = nullptr; filter_to_ = nullptr; @@ -786,13 +787,6 @@ Search::arrivalInvalid(Vertex *vertex) } } -void -Search::arrivalInvalidDelete(Vertex *vertex) -{ - arrivalInvalid(vertex); - deletePaths(vertex); -} - void Search::levelChangedBefore(Vertex *vertex) { @@ -1072,7 +1066,8 @@ Search::findArrivalsSeed() //////////////////////////////////////////////////////////////// ArrivalVisitor::ArrivalVisitor(const StaState *sta) : - PathVisitor(nullptr, sta) + PathVisitor(nullptr, sta), + always_save_prev_paths_(true) { init0(); init(true); @@ -1109,6 +1104,8 @@ ArrivalVisitor::init(bool always_to_endpoints, always_to_endpoints_ = always_to_endpoints; pred_ = pred; crpr_active_ = sdc_->crprActive(); + if (search_) + always_save_prev_paths_ = search_->alwaysSavePrevPaths(); } @@ -1241,6 +1238,7 @@ Search::arrivalsChanged(Vertex *vertex, TagGroupBldr *tag_bldr) { Arrival *arrivals1 = graph_->arrivals(vertex); + PathPrev *prev_paths1 = graph_->prevPaths(vertex); if (arrivals1) { TagGroup *tag_group = tagGroup(vertex); if (tag_group == nullptr @@ -1257,7 +1255,10 @@ Search::arrivalsChanged(Vertex *vertex, int arrival_index2; tag_bldr->tagMatchArrival(tag1, tag2, arrival2, arrival_index2); if (tag2 != tag1 - || !delayEqual(arrival1, arrival2)) + || !delayEqual(arrival1, arrival2) + || (prev_paths1 + && !PathPrev::equal(prev_paths1[arrival_index1], + tag_bldr->prevPath(arrival_index2)))) return true; } return false; @@ -1273,10 +1274,10 @@ ArrivalVisitor::visitFromToPath(const Pin *, Tag *from_tag, PathVertex *from_path, const Arrival &from_arrival, - Edge *, - TimingArc *, + Edge *edge, + TimingArc *arc, ArcDelay arc_delay, - Vertex *, + Vertex * /* to_vertex */, const RiseFall *to_rf, Tag *to_tag, Arrival &to_arrival, @@ -1307,9 +1308,13 @@ ArrivalVisitor::visitFromToPath(const Pin *, delayAsString(to_arrival, this), min_max == MinMax::max() ? ">" : "<", tag_match ? delayAsString(arrival, this) : "MIA"); - PathVertexRep prev_path; - if (to_tag->isClock() || to_tag->isGenClkSrcPath()) - prev_path.init(from_path, this); + PathPrev prev_path; + bool always_save_prev_paths = true; + bool save_prev = always_save_prev_paths + || to_tag->isClock() + || to_tag->isGenClkSrcPath(); + if (save_prev) + prev_path.init(from_path, edge, arc, this); tag_bldr_->setMatchArrival(to_tag, tag_match, to_arrival, arrival_index, &prev_path); @@ -1333,13 +1338,13 @@ ArrivalVisitor::visitFromToPath(const Pin *, void ArrivalVisitor::pruneCrprArrivals() { - ArrivalMap::Iterator arrival_iter(tag_bldr_->arrivalMap()); CheckCrpr *crpr = search_->checkCrpr(); - while (arrival_iter.hasNext()) { - Tag *tag; - int arrival_index; - arrival_iter.next(tag, arrival_index); + ArrivalMap *arrival_map = tag_bldr_->arrivalMap(); + for (auto arrival_itr = arrival_map->cbegin(); arrival_itr != arrival_map->cend(); ) { + Tag *tag = arrival_itr->first; + int arrival_index = arrival_itr->second; ClkInfo *clk_info = tag->clkInfo(); + bool deleted_tag = false; if (!tag->isClock() && clk_info->hasCrprClkPin()) { PathAnalysisPt *path_ap = tag->pathAnalysisPt(this); @@ -1364,10 +1369,13 @@ ArrivalVisitor::pruneCrprArrivals() if (delayGreater(max_arrival_max_crpr, arrival, min_max, this)) { debugPrint(debug_, "search", 3, " pruned %s", tag->asString(this)); - tag_bldr_->deleteArrival(tag); + arrival_itr = arrival_map->erase(arrival_itr); + deleted_tag = true; } } } + if (!deleted_tag) + arrival_itr++; } } @@ -2710,7 +2718,10 @@ Search::setVertexArrivals(Vertex *vertex, else { TagGroup *prev_tag_group = tagGroup(vertex); Arrival *prev_arrivals = graph_->arrivals(vertex); - PathVertexRep *prev_paths = graph_->prevPaths(vertex); + PathPrev *prev_paths = graph_->prevPaths(vertex); + bool save_prev = always_save_prev_paths_ + || tag_bldr->hasClkTag() + || tag_bldr->hasGenClkSrcTag(); TagGroup *tag_group = findTagGroup(tag_bldr); int arrival_count = tag_group->arrivalCount(); @@ -2718,7 +2729,7 @@ Search::setVertexArrivals(Vertex *vertex, // Reuse arrival array if it is the same size. if (prev_tag_group && arrival_count == prev_tag_group->arrivalCount()) { - if (tag_bldr->hasClkTag() || tag_bldr->hasGenClkSrcTag()) { + if (save_prev) { if (prev_paths == nullptr) prev_paths = graph_->makePrevPaths(vertex, arrival_count); } @@ -2751,7 +2762,7 @@ Search::setVertexArrivals(Vertex *vertex, } Arrival *arrivals = graph_->makeArrivals(vertex, arrival_count); prev_paths = nullptr; - if (tag_bldr->hasClkTag() || tag_bldr->hasGenClkSrcTag()) + if (save_prev) prev_paths = graph_->makePrevPaths(vertex, arrival_count); tag_bldr->copyArrivals(tag_group, arrivals, prev_paths); @@ -2771,6 +2782,7 @@ Search::reportArrivals(Vertex *vertex) const TagGroup *tag_group = tagGroup(vertex); Arrival *arrivals = graph_->arrivals(vertex); Required *requireds = graph_->requireds(vertex); + PathPrev *prev_paths = graph_->prevPaths(vertex); if (tag_group) { report_->reportLine("Group %u", tag_group->index()); ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap()); @@ -2791,14 +2803,34 @@ Search::reportArrivals(Vertex *vertex) const if (!prev.isNull()) clk_prev = prev.name(this); } - report_->reportLine(" %d %s %s %s / %s %s %s", + string prev_str; + if (prev_paths) { + PathPrev &prev = prev_paths[arrival_index]; + if (!prev.isNull()) { + prev_str += prev.name(this); + prev_str += " "; + const Edge *prev_edge = prev.prevEdge(this); + TimingArc *arc = prev.prevArc(this); + prev_str += prev_edge->from(graph_)->name(network_); + prev_str += " "; + prev_str += arc->fromEdge()->asString(); + prev_str += " -> "; + prev_str += prev_edge->to(graph_)->name(network_); + prev_str += " "; + prev_str += arc->toEdge()->asString(); + } + else + prev_str = "NULL"; + } + report_->reportLine(" %d %s %s %s / %s %s %s prev %s", arrival_index, rf->asString(), path_ap->pathMinMax()->asString(), delayAsString(arrivals[arrival_index], this), req, tag->asString(true, false, this), - clk_prev); + clk_prev, + prev_str.c_str()); } } else @@ -2983,17 +3015,17 @@ Search::findClkInfo(const ClockEdge *clk_edge, const PathAnalysisPt *path_ap, PathVertex *crpr_clk_path) { - PathVertexRep crpr_clk_path_rep(crpr_clk_path, this); + PathVertexPtr crpr_clk_path_ptr(crpr_clk_path, this); ClkInfo probe(clk_edge, clk_src, is_propagated, gen_clk_src, gen_clk_src_path, pulse_clk_sense, insertion, latency, uncertainties, - path_ap->index(), crpr_clk_path_rep, this); + path_ap->index(), crpr_clk_path_ptr, this); LockGuard lock(clk_info_lock_); ClkInfo *clk_info = clk_info_set_->findKey(&probe); if (clk_info == nullptr) { clk_info = new ClkInfo(clk_edge, clk_src, is_propagated, gen_clk_src, gen_clk_src_path, pulse_clk_sense, insertion, latency, uncertainties, - path_ap->index(), crpr_clk_path_rep, this); + path_ap->index(), crpr_clk_path_ptr, this); clk_info_set_->insert(clk_info); } return clk_info; diff --git a/search/Sta.cc b/search/Sta.cc index d01b0057..48ad81b4 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -4609,8 +4609,7 @@ Sta::deletePinBefore(const Pin *pin) if (edge->role()->isWire()) { // Only notify to vertex (from will be deleted). Vertex *to = edge->to(graph_); - // to->prev_paths point to vertex, so delete them. - search_->arrivalInvalidDelete(to); + search_->arrivalInvalid(to); graph_delay_calc_->delayInvalid(to); levelize_->relevelizeFrom(to); } diff --git a/search/TagGroup.cc b/search/TagGroup.cc index b00ed4c6..14d6bb89 100644 --- a/search/TagGroup.cc +++ b/search/TagGroup.cc @@ -32,7 +32,7 @@ #include "Tag.hh" #include "Corner.hh" #include "Search.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" namespace sta { @@ -200,7 +200,7 @@ TagGroupBldr::arrival(int arrival_index) const void TagGroupBldr::setArrival(Tag *tag, const Arrival &arrival, - PathVertexRep *prev_path) + PathPrev *prev_path) { Tag *tag_match; Arrival ignore; @@ -215,7 +215,7 @@ TagGroupBldr::setMatchArrival(Tag *tag, Tag *tag_match, const Arrival &arrival, int arrival_index, - PathVertexRep *prev_path) + PathPrev *prev_path) { if (tag_match) { // If the group_tag exists there has to be an arrival map entry for it. @@ -234,7 +234,7 @@ TagGroupBldr::setMatchArrival(Tag *tag, if (prev_path) prev_paths_.push_back(*prev_path); else - prev_paths_.push_back(PathVertexRep()); + prev_paths_.push_back(PathPrev()); if (tag->isClock()) has_clk_tag_ = true; @@ -248,12 +248,6 @@ TagGroupBldr::setMatchArrival(Tag *tag, } } -void -TagGroupBldr::deleteArrival(Tag *tag) -{ - arrival_map_.erase(tag); -} - TagGroup * TagGroupBldr::makeTagGroup(TagGroupIndex index, const StaState *sta) @@ -285,7 +279,7 @@ TagGroupBldr::makeArrivalMap(const StaState *sta) void TagGroupBldr::copyArrivals(TagGroup *tag_group, Arrival *arrivals, - PathVertexRep *prev_paths) + PathPrev *prev_paths) { ArrivalMap::Iterator arrival_iter1(arrival_map_); while (arrival_iter1.hasNext()) { @@ -297,7 +291,7 @@ TagGroupBldr::copyArrivals(TagGroup *tag_group, if (exists2) { arrivals[arrival_index2] = arrivals_[arrival_index1]; if (prev_paths) { - PathVertexRep *prev_path = &prev_paths_[arrival_index1]; + PathPrev *prev_path = &prev_paths_[arrival_index1]; prev_paths[arrival_index2].init(prev_path); } } @@ -306,6 +300,12 @@ TagGroupBldr::copyArrivals(TagGroup *tag_group, } } +PathPrev & +TagGroupBldr::prevPath(int arrival_index) +{ + return prev_paths_[arrival_index]; +} + //////////////////////////////////////////////////////////////// size_t diff --git a/search/TagGroup.hh b/search/TagGroup.hh index eca1d26a..64082d80 100644 --- a/search/TagGroup.hh +++ b/search/TagGroup.hh @@ -37,7 +37,7 @@ namespace sta { class TagGroupBldr; -typedef Vector PathVertexRepSeq; +typedef Vector PathPrevSeq; class TagGroup { @@ -110,7 +110,6 @@ public: bool hasGenClkSrcTag() const { return has_genclk_src_tag_; } bool hasFilterTag() const { return has_filter_tag_; } bool hasLoopTag() const { return has_loop_tag_; } - void deleteArrival(Tag *tag); void tagMatchArrival(Tag *tag, // Return values. Tag *&tag_match, @@ -119,16 +118,17 @@ public: Arrival arrival(int arrival_index) const; void setArrival(Tag *tag, const Arrival &arrival, - PathVertexRep *prev_path); + PathPrev *prev_path); void setMatchArrival(Tag *tag, Tag *tag_match, const Arrival &arrival, int arrival_index, - PathVertexRep *prev_path); + PathPrev *prev_path); ArrivalMap *arrivalMap() { return &arrival_map_; } + PathPrev &prevPath(int arrival_index); void copyArrivals(TagGroup *tag_group, Arrival *arrivals, - PathVertexRep *prev_paths); + PathPrev *prev_paths); protected: int tagMatchIndex(); @@ -138,7 +138,7 @@ protected: int default_arrival_count_; ArrivalMap arrival_map_; ArrivalSeq arrivals_; - PathVertexRepSeq prev_paths_; + PathPrevSeq prev_paths_; bool has_clk_tag_; bool has_genclk_src_tag_:1; bool has_filter_tag_;