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_;