Fix levelize crash when vertices enqueued in arrival/required iterators

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-05-15 17:21:39 -07:00
parent 3e6bbf46d5
commit b32eed9a84
5 changed files with 52 additions and 8 deletions

View File

@ -359,6 +359,7 @@ public:
void reportArrivals(Vertex *vertex) const;
Slack wnsSlack(Vertex *vertex,
PathAPIndex path_ap_index);
void levelsChangedBefore();
void levelChangedBefore(Vertex *vertex);
void seedInputArrival(const Pin *pin,
Vertex *vertex,

View File

@ -122,6 +122,8 @@ Levelize::levelize()
Stats stats(debug_, report_);
debugPrint(debug_, "levelize", 1, "levelize");
clear();
if (observer_)
observer_->levelsChangedBefore();
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
@ -545,6 +547,19 @@ Levelize::ensureLatchLevels()
latch_d_to_q_edges_.clear();
}
void
Levelize::setLevel(Vertex *vertex,
Level level)
{
debugPrint(debug_, "levelize", 2, "set level %s %d",
vertex->to_string(this).c_str(),
level);
vertex->setLevel(level);
max_level_ = max(level, max_level_);
if (level >= Graph::vertex_level_max)
criticalError(616, "maximum logic level exceeded");
}
void
Levelize::invalid()
{
@ -597,6 +612,8 @@ Levelize::deleteEdgeBefore(Edge *edge)
{
if (levelized_
&& loop_edges_.hasKey(edge)) {
debugPrint(debug_, "levelize", 2, "delete loop edge %s",
edge->to_string(this).c_str());
disabled_loop_edges_.erase(edge);
// Relevelize if a loop edge is removed. Incremental levelization
// fails because the DFS path will be missing.
@ -621,7 +638,7 @@ Levelize::relevelize()
vertex->to_string(this).c_str());
if (search_pred_.searchFrom(vertex)) {
if (isRoot(vertex)) {
setLevel(vertex, 0);
setLevelIncr(vertex, 0);
roots_->insert(vertex);
}
VertexSet visited(graph_);
@ -645,7 +662,7 @@ Levelize::visit(Vertex *vertex,
EdgeSeq &path)
{
Pin *from_pin = vertex->pin();
setLevel(vertex, level);
setLevelIncr(vertex, level);
level += level_space;
visited.insert(vertex);
path_vertices.insert(vertex);
@ -691,8 +708,8 @@ Levelize::isDisabledLoop(Edge *edge) const
}
void
Levelize::setLevel(Vertex *vertex,
Level level)
Levelize::setLevelIncr(Vertex *vertex,
Level level)
{
debugPrint(debug_, "levelize", 2, "set level %s %d",
vertex->to_string(this).c_str(),
@ -704,7 +721,7 @@ Levelize::setLevel(Vertex *vertex,
}
max_level_ = max(level, max_level_);
if (level >= Graph::vertex_level_max)
criticalError(616, "maximum logic level exceeded");
criticalError(617, "maximum logic level exceeded");
}
////////////////////////////////////////////////////////////////

View File

@ -96,6 +96,8 @@ protected:
EdgeSeq &path);
void setLevel(Vertex *vertex,
Level level);
void setLevelIncr(Vertex *vertex,
Level level);
void clearLoopEdges();
void deleteLoops();
void reportPath(EdgeSeq &path) const;
@ -135,6 +137,7 @@ class LevelizeObserver
public:
LevelizeObserver() {}
virtual ~LevelizeObserver() {}
virtual void levelsChangedBefore() = 0;
virtual void levelChangedBefore(Vertex *vertex) = 0;
};

View File

@ -795,14 +795,30 @@ Search::arrivalInvalid(Vertex *vertex)
}
}
// Move any pending arrival/requireds to invalid before relevelization.
void
Search::levelsChangedBefore()
{
if (arrivals_exist_) {
while (arrival_iter_->hasNext()) {
Vertex *vertex = arrival_iter_->next();
arrivalInvalid(vertex);
}
while (required_iter_->hasNext()) {
Vertex *vertex = required_iter_->next();
requiredInvalid(vertex);
}
}
}
void
Search::levelChangedBefore(Vertex *vertex)
{
if (arrivals_exist_) {
arrival_iter_->remove(vertex);
required_iter_->remove(vertex);
search_->arrivalInvalid(vertex);
search_->requiredInvalid(vertex);
arrivalInvalid(vertex);
requiredInvalid(vertex);
}
}

View File

@ -210,7 +210,8 @@ class StaLevelizeObserver : public LevelizeObserver
{
public:
StaLevelizeObserver(Search *search);
virtual void levelChangedBefore(Vertex *vertex);
void levelsChangedBefore() override;
void levelChangedBefore(Vertex *vertex) override;
private:
Search *search_;
@ -221,6 +222,12 @@ StaLevelizeObserver::StaLevelizeObserver(Search *search) :
{
}
void
StaLevelizeObserver::levelsChangedBefore()
{
search_->levelsChangedBefore();
}
void
StaLevelizeObserver::levelChangedBefore(Vertex *vertex)
{