OpenSTA/search/VisitPathGroupVertices.cc

322 lines
9.1 KiB
C++

// OpenSTA, Static Timing Analyzer
// Copyright (c) 2020, 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 <https://www.gnu.org/licenses/>.
#include "VisitPathGroupVertices.hh"
#include "Debug.hh"
#include "Graph.hh"
#include "Bfs.hh"
#include "Search.hh"
#include "PathVertex.hh"
#include "PathEnd.hh"
#include "Tag.hh"
#include "VisitPathEnds.hh"
namespace sta {
typedef Set<PathVertex*, PathLess> PathVertexSet;
typedef Map<Vertex*, PathVertexSet*> VertexPathSetMap;
static void
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
Vertex *vertex,
Tag *tag,
int arrival_index,
const StaState *sta);
// Visit each path end for a vertex and add the worst one in each
// path group to the group.
class VisitPathGroupEnds : public PathEndVisitor
{
public:
explicit VisitPathGroupEnds(PathGroup *path_group,
VertexVisitor *vertex_visitor,
VertexPathSetMap *matching_path_map,
BfsBkwdIterator *bkwd_iter,
StaState *sta);
virtual PathEndVisitor *copy();
virtual void visit(PathEnd *path_end);
virtual void vertexBegin(Vertex *vertex);
virtual void vertexEnd(Vertex *vertex);
private:
DISALLOW_COPY_AND_ASSIGN(VisitPathGroupEnds);
PathGroup *path_group_;
VertexVisitor *vertex_visitor_;
BfsBkwdIterator *bkwd_iter_;
VertexPathSetMap *matching_path_map_;
bool vertex_matches_;
StaState *sta_;
};
class PathGroupPathVisitor : public PathVisitor
{
public:
PathGroupPathVisitor(VertexVisitor *visitor,
BfsBkwdIterator *bkwd_iter,
VertexPathSetMap *matching_path_map,
const StaState *sta);
virtual ~PathGroupPathVisitor();
virtual VertexVisitor *copy();
virtual void visit(Vertex *vertex);
protected:
// Return false to stop visiting.
virtual bool visitFromToPath(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
Vertex *to_vertex,
const RiseFall *to_rf,
Tag *to_tag,
Arrival &to_arrival,
const MinMax *min_max,
const PathAnalysisPt *path_ap);
void fromMatches(Vertex *from_vertex,
Tag *from_tag,
int from_arrival_index);
private:
VertexVisitor *visitor_;
BfsBkwdIterator *bkwd_iter_;
VertexPathSetMap *matching_path_map_;
bool vertex_matches_;
};
////////////////////////////////////////////////////////////////
// Visit the fanin vertices for the path group.
// Vertices in the clock network are NOT visited.
void
visitPathGroupVertices(PathGroup *path_group,
VertexVisitor *visitor,
StaState *sta)
{
Search *search = sta->search();
VertexPathSetMap matching_path_map;
// Do not visit clock network.
SearchPredNonReg2 srch_non_reg(sta);
BfsBkwdIterator bkwd_iter(BfsIndex::other, &srch_non_reg, sta);
// Visit the path ends and filter by path_group to seed the backward search.
VisitPathGroupEnds end_visitor(path_group, visitor, &matching_path_map,
&bkwd_iter, sta);
VisitPathEnds visit_path_ends(sta);
VertexSet::Iterator end_iter(search->endpoints());
while (end_iter.hasNext()) {
Vertex *vertex = end_iter.next();
visit_path_ends.visitPathEnds(vertex, &end_visitor);
}
// Search backward from the path ends thru vertices that have arrival tags
// that match path_group end paths.
PathGroupPathVisitor path_visitor(visitor, &bkwd_iter, &matching_path_map,
sta);
bkwd_iter.visit(0, &path_visitor);
// Cleanup.
VertexPathSetMap::Iterator matching_iter(matching_path_map);
while (matching_iter.hasNext()) {
PathVertexSet *paths = matching_iter.next();
PathVertexSet::Iterator path_iter(paths);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
delete path;
}
delete paths;
}
}
////////////////////////////////////////////////////////////////
VisitPathGroupEnds::VisitPathGroupEnds(PathGroup *path_group,
VertexVisitor *vertex_visitor,
VertexPathSetMap *matching_path_map,
BfsBkwdIterator *bkwd_iter,
StaState *sta) :
path_group_(path_group),
vertex_visitor_(vertex_visitor),
bkwd_iter_(bkwd_iter),
matching_path_map_(matching_path_map),
sta_(sta)
{
}
PathEndVisitor *
VisitPathGroupEnds::copy()
{
return new VisitPathGroupEnds(path_group_, vertex_visitor_,
matching_path_map_, bkwd_iter_, sta_);
}
void
VisitPathGroupEnds::vertexBegin(Vertex *)
{
vertex_matches_ = false;
}
void
VisitPathGroupEnds::visit(PathEnd *path_end)
{
PathGroup *group = sta_->search()->pathGroup(path_end);
if (group == path_group_) {
PathRef path(path_end->pathRef());
Vertex *vertex = path.vertex(sta_);
int arrival_index;
bool arrival_exists;
path.arrivalIndex(arrival_index, arrival_exists);
vertexPathSetMapInsertPath(matching_path_map_, vertex, path.tag(sta_),
arrival_index, sta_);
vertex_matches_ = true;
}
}
static void
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
Vertex *vertex,
Tag *tag,
int arrival_index,
const StaState *sta)
{
PathVertexSet *matching_paths = matching_path_map->findKey(vertex);
if (matching_paths == nullptr) {
PathLess path_less(sta);
matching_paths = new PathVertexSet(path_less);
(*matching_path_map)[vertex] = matching_paths;
}
PathVertex *vpath = new PathVertex(vertex, tag, arrival_index);
matching_paths->insert(vpath);
}
void
VisitPathGroupEnds::vertexEnd(Vertex *vertex)
{
if (vertex_matches_) {
vertex_visitor_->visit(vertex);
// Seed backward bfs fanin search.
bkwd_iter_->enqueueAdjacentVertices(vertex);
}
}
////////////////////////////////////////////////////////////////
PathGroupPathVisitor::PathGroupPathVisitor(VertexVisitor *visitor,
BfsBkwdIterator *bkwd_iter,
VertexPathSetMap *matching_path_map,
const StaState *sta) :
PathVisitor(sta),
visitor_(visitor),
bkwd_iter_(bkwd_iter),
matching_path_map_(matching_path_map)
{
}
PathGroupPathVisitor::~PathGroupPathVisitor()
{
}
VertexVisitor *
PathGroupPathVisitor::copy()
{
return new PathGroupPathVisitor(visitor_, bkwd_iter_, matching_path_map_,
sta_);
}
void
PathGroupPathVisitor::visit(Vertex *vertex)
{
vertex_matches_ = false;
visitFanoutPaths(vertex);
if (vertex_matches_) {
const Debug *debug = sta_->debug();
debugPrint(debug, "visit_path_group", 1, "visit %s",
vertex->name(sta_->network()));
visitor_->visit(vertex);
bkwd_iter_->enqueueAdjacentVertices(vertex);
}
}
bool
PathGroupPathVisitor::visitFromToPath(const Pin *,
Vertex *from_vertex,
const RiseFall *,
Tag *from_tag,
PathVertex *from_path,
Edge *,
TimingArc *,
ArcDelay ,
Vertex *to_vertex,
const RiseFall *to_rf,
Tag *to_tag,
Arrival &,
const MinMax *,
const PathAnalysisPt *path_ap)
{
PathVertexSet *matching_paths = matching_path_map_->findKey(to_vertex);
if (matching_paths) {
int arrival_index;
bool arrival_exists;
from_path->arrivalIndex(arrival_index, arrival_exists);
PathVertex to_path(to_vertex, to_tag, sta_);
if (!to_path.isNull()) {
if (matching_paths->hasKey(&to_path)) {
const Debug *debug = sta_->debug();
debugPrint(debug, "visit_path_group", 2, "match %s %s -> %s %s",
from_vertex->name(sta_->network()),
from_tag->asString(sta_),
to_vertex->name(sta_->network()),
to_tag->asString(sta_));
fromMatches(from_vertex, from_tag, arrival_index);
}
}
else {
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, sta_);
while (to_iter.hasNext()) {
PathVertex *to_path = to_iter.next();
if (tagMatchNoCrpr(to_path->tag(sta_), to_tag)
&& matching_paths->hasKey(to_path)) {
const Debug *debug = sta_->debug();
debugPrint(debug, "visit_path_group", 2,
"match crpr %s %s -> %s %s",
from_vertex->name(sta_->network()),
from_tag->asString(sta_),
to_vertex->name(sta_->network()),
to_tag->asString(sta_));
fromMatches(from_vertex, from_tag, arrival_index);
}
}
}
}
return true;
}
void
PathGroupPathVisitor::fromMatches(Vertex *from_vertex,
Tag *from_tag,
int from_arrival_index)
{
vertex_matches_ = true;
vertexPathSetMapInsertPath(matching_path_map_, from_vertex,
from_tag, from_arrival_index, sta_);
}
} // namespace