rsz: build equivalence classes without the liberty dont_use filter - #11042
rsz: build equivalence classes without the liberty dont_use filter#11042dsengupta0628 wants to merge 2 commits into
Conversation
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
There was a problem hiding this comment.
Code Review
This pull request refactors how cell equivalence classes are managed, moving the logic from OpenSTA's equivalence table directly into the Resizer. This allows cells that are marked as dont_use in liberty but subsequently re-enabled with unset_dont_use to remain viable sizing candidates. The review feedback points out two critical robustness issues: a potential null pointer dereference in Timing::equivCells if the resizer is unavailable, and another potential null pointer dereference in equivCellKey if a port lacks a defined direction.
| sta::LibertyCellSeq* equiv_cells = resizer->equivCells(libcell); | ||
| if (equiv_cells) { | ||
| for (sta::LibertyCell* equiv_cell : *equiv_cells) { | ||
| // The classes are built without dont_use filtering. The cell asked | ||
| // about is always reported, dont_use or not. | ||
| if (equiv_cell != libcell && resizer->dontUse(equiv_cell)) { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
If design_->getResizer() returns nullptr (e.g., if the resizer is not initialized or not available in the current session), calling resizer->equivCells(libcell) and resizer->dontUse(equiv_cell) will result in a segmentation fault. Adding a null check for resizer and falling back to sta->equivCells(libcell) ensures robustness.
| sta::LibertyCellSeq* equiv_cells = resizer->equivCells(libcell); | |
| if (equiv_cells) { | |
| for (sta::LibertyCell* equiv_cell : *equiv_cells) { | |
| // The classes are built without dont_use filtering. The cell asked | |
| // about is always reported, dont_use or not. | |
| if (equiv_cell != libcell && resizer->dontUse(equiv_cell)) { | |
| continue; | |
| } | |
| sta::LibertyCellSeq* equiv_cells = resizer ? resizer->equivCells(libcell) : sta->equivCells(libcell); | |
| if (equiv_cells) { | |
| for (sta::LibertyCell* equiv_cell : *equiv_cells) { | |
| // The classes are built without dont_use filtering. The cell asked | |
| // about is always reported, dont_use or not. | |
| if (equiv_cell != libcell && resizer && resizer->dontUse(equiv_cell)) { | |
| continue; | |
| } |
| static unsigned equivCellKey(const sta::LibertyCell* cell) | ||
| { | ||
| unsigned key = 0; | ||
| sta::LibertyCellPortIterator port_iter(cell); | ||
| while (port_iter.hasNext()) { | ||
| const sta::LibertyPort* port = port_iter.next(); | ||
| key += sta::hashString(port->name()) * 3 + port->direction()->index() * 5; | ||
| } | ||
| return key; | ||
| } |
There was a problem hiding this comment.
In Liberty files, some ports (such as special or malformed ports) might not have a defined direction, causing port->direction() to return nullptr. Dereferencing it directly with port->direction()->index() will lead to a segmentation fault. Adding a null check for port->direction() prevents potential crashes.
static unsigned equivCellKey(const sta::LibertyCell* cell)
{
unsigned key = 0;
sta::LibertyCellPortIterator port_iter(cell);
while (port_iter.hasNext()) {
const sta::LibertyPort* port = port_iter.next();
const sta::PortDirection* dir = port->direction();
unsigned dir_index = dir ? dir->index() : 0;
key += sta::hashString(port->name()) * 3 + dir_index * 5;
}
return key;
}|
Gemini hallucination in review:
|
Problem
unset_dont_usehad no effect on sizing. OpenROAD keeps "don't use" in twoplaces: the liberty attribute
sta::LibertyCell::dont_use_, written only by theliberty reader, and the resizer's effective policy
rsz::Resizer::dont_use_,written by
set_dont_use/unset_dont_useand seeded from liberty bycopyDontUseFromLiberty().sta::EquivCellsfilters on the liberty attribute,so a cell re-enabled with
unset_dont_usenever entered the equivalence table:getSwappableCellsgot a null class, returned only the source cell, and theinstance stayed at its original drive.
This bites vendor flows that mark a multibit-flop family
dont_usein libertyand re-enable it before clustering.
MBFF::IsValidTrayconsults onlyResizer::dont_use_, so clustering produced the trays; sizing then could notfind a single candidate for them and the flops stayed at minimum drive with bad
slew.
Change
The resizer builds its own equivalence classes over the link cells instead of
calling
sta::Sta::makeEquivCells, with nodont_usefiltering of any kind.Policy is applied at query time, where
swappable_cells_cache_invalidationalready lives. Bucketing uses a necessary condition (
sta::hashCell's portterm) and classes are refined with the public
sta::equivCells(), so theequivalence maths is unchanged.
src/stais untouched. Consolidating the twodont_usefields is the real fixand is deferred for now; this index can be deleted then.
Two latent problems surfaced and are fixed here because they blocked the above:
getSwappableCellsnow returns{source_cell}for adont_usesource. Oncesuch a cell had a real class, the filter dropped the source itself and left
only the other members, so instances of
dont_usecells were sized awayagainst a
target_load_map_baseline of 0 (maximum distance, any candidatewins).
target_load_map_is reset insetDontUse/resetDontUse/postReadLiberty. It was built once excludingdont_usecells and neverrebuilt, so
unset_dont_useissued after a preamble left the re-enabled cellswith target load 0 and ranked them worst.
Timing::equivCellsmoves to the resizer index, appliesdontUse, alwaysreports the queried cell, and null-checks
staToDb. The GUI keeps its own STAtable; now that rsz no longer touches it, it can no longer clobber the resizer
mid-session.
Test
src/rsz/test/unset_dont_use_equiv_cells.tcl, registered in CMake and Bazel.Nangate45
FILLCELL_X*is a liberty-dont_usefamily with drive variants, sono synthetic
.libis needed.report_equiv_cells FILLCELL_X1gives 1candidate (itself, matching stock upstream) and 3 after
unset_dont_use;set_dont_use BUF_X4then drops it fromBUF_X2's list, showing policy isapplied at query time and not baked into the index.
Type of Change
Impact
improves slew after MBFF clustering and resizing
Verification
./etc/Build.sh).