Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/dbSta/test/cpp/TestDbSta.cc
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ TEST_F(TestDbSta, ReassociateModITermPin)
db_network_->checkAxioms();
}

// Regression for #10210 (stale Path* dereference in rsz).
// Regression for #10210 (stale Path* dereference in rsz) and the rsz-side
// resetSearchAfterRepair() mitigation.
//
// Topology (TestDbSta_StalePrevPath.v):
// clk -> b1(BUF) -> inv1(INV) -> nd1(NAND2) -> out1
Expand All @@ -277,6 +278,9 @@ TEST_F(TestDbSta, ReassociateModITermPin)
// 4. Assert the captured Path's prev slot has been recycled: pin()
// decodes to data that belongs to a different instance than nd1's
// real input.
// 5. Apply the rsz mitigation (Resizer::resetSearchAfterRepair) and assert a
// fresh worst-path lookup is clean -- every node's vertex resolves, so no
// recycled slot survives for CheckCrpr::findCrpr to walk.
TEST_F(TestDbSta, StalePrevPath)
{
const auto* test_info = testing::UnitTest::GetInstance()->current_test_info();
Expand Down Expand Up @@ -329,6 +333,21 @@ TEST_F(TestDbSta, StalePrevPath)
EXPECT_NE(pre_pin_name, post_pin_name)
<< "but slot content should differ after free+reuse. before="
<< pre_pin_name << " after=" << post_pin_name;

// 5. rsz's #10210 mitigation: repair_timing runs resetSearchAfterRepair() at
// its end. Dropping the interned search state must make a fresh
// worst-path lookup clean again -- every node's vertex resolves, so no
// recycled slot survives for CheckCrpr::findCrpr to walk.
resizer_.resetSearchAfterRepair();
Path* fixed_path = sta_->vertexWorstArrivalPath(
sta_->ensureGraph()->pinDrvrVertex(network->findPin(nd1, "ZN")),
MinMax::max());
ASSERT_NE(fixed_path, nullptr);
EXPECT_EQ(network->pathName(fixed_path->pin(sta_.get())), "nd1/ZN");
for (const Path* p = fixed_path; p != nullptr; p = p->prevPath()) {
EXPECT_NE(p->vertex(sta_.get()), nullptr)
<< "reset left a stale path node for findCrpr to walk";
}
}

} // namespace sta
5 changes: 5 additions & 0 deletions src/rsz/include/rsz/Resizer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,11 @@ class Resizer : public sta::dbStaState, public sta::dbNetworkObserver
int max_passes);
int holdBufferCount() const;

// Drop interned STA search state and recompute timing so a stale CRPR clock
// path left by incremental repairs is not walked later (#10210 workaround;
// graph/parasitics/delays kept). See the definition.
void resetSearchAfterRepair();

////////////////////////////////////////////////////////////////
bool recoverPower(float recover_power_percent,
bool match_cell_footprint,
Expand Down
14 changes: 14 additions & 0 deletions src/rsz/src/Resizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5049,6 +5049,20 @@ int Resizer::holdBufferCount() const
return repair_hold_->holdBufferCount();
}

void Resizer::resetSearchAfterRepair()
{
// Workaround for #10210; the root fix belongs in OpenSTA. repair_timing's
// incremental updates recycle the per-vertex Path arena, but a CRPR clock
// path cached in an interned ClkInfo/Tag keeps a raw prev_path_ into the
// freed slot, so a later CheckCrpr::findCrpr (e.g. report_metrics) walks a
// dangling chain and aborts. Drop the interned search state so the next
// analysis rebuilds clean; graph/parasitics/delays are kept, only arrivals
// are recomputed. Proper fix: findCrpr should re-resolve clock-path nodes
// from stable graph ids, not raw prev_path_. TODO(#10210): remove when fixed.
search_->clear();
sta_->updateTiming(/*full=*/true);
}

////////////////////////////////////////////////////////////////
bool Resizer::recoverPower(float recover_power_percent,
bool match_cell_footprint,
Expand Down
8 changes: 8 additions & 0 deletions src/rsz/src/Resizer.i
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,14 @@ repair_hold_pin(Pin *end_pin,
max_buffer_percent, max_passes);
}

void
reset_search_after_repair()
{
ensureLinked();
Resizer *resizer = getResizer();
resizer->resetSearchAfterRepair();
}

int
hold_buffer_count()
{
Expand Down
9 changes: 8 additions & 1 deletion src/rsz/src/Resizer.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,14 @@ proc repair_timing { args } {
}
}

return [expr $recovered_power || $repaired_setup || $repaired_hold]
set repaired [expr $recovered_power || $repaired_setup || $repaired_hold]
if { $repaired } {
# Workaround for #10210: incremental repairs can leave a stale CRPR clock
# path that crashes a later report; drop the search state so it rebuilds
# clean. Remove when fixed in OpenSTA. See Resizer::resetSearchAfterRepair.
rsz::reset_search_after_repair
}
return $repaired
}

################################################################
Expand Down
Loading