diff --git a/liberty/EquivCells.cc b/liberty/EquivCells.cc index 6afca9c9..64a2ff4b 100644 --- a/liberty/EquivCells.cc +++ b/liberty/EquivCells.cc @@ -15,7 +15,6 @@ // along with this program. If not, see . #include "Machine.hh" -#include "UnorderedMap.hh" #include "PortDirection.hh" #include "Transition.hh" #include "MinMax.hh" @@ -31,17 +30,6 @@ namespace sta { using std::max; -typedef UnorderedMap LibertyCellHashMap; -typedef Set LibertyCellSet; - -static void -findEquivCells1(const LibertyLibrary *library, - LibertyCellSet &cell_equivs); -static void -sortCellEquivs(LibertyCellSet &cell_equivs); -static float -cellDriveResistance(const LibertyCell *cell); - static unsigned hashCell(const LibertyCell *cell); static unsigned @@ -55,91 +43,110 @@ hashPort(const LibertyPort *port); static unsigned hashString(const char *str); -static bool -equivCellSequentials(const LibertyCell *cell1, - const LibertyCell *cell2); - -void -findEquivCells(const LibertyLibrary *library) +class CellDriveResistanceLess { - LibertyCellSet cell_equivs; - findEquivCells1(library, cell_equivs); - // Sort by drive strength. - sortCellEquivs(cell_equivs); +public: + bool operator()(const LibertyCell *cell1, + const LibertyCell *cell2) const + { + return cell1->driveResistance() > cell2->driveResistance(); + } +}; + +EquivCells::EquivCells(LibertyLibrarySeq *equiv_libs, + LibertyLibrarySeq *map_libs) +{ + LibertyCellHashMap hash_matches; + for (auto lib : *equiv_libs) + findEquivCells(lib, hash_matches); + // Sort the equiv sets by drive resistance. + for (auto cell : unique_equiv_cells_) { + auto equivs = equiv_cells_.findKey(cell); + sort(equivs, CellDriveResistanceLess()); + } + if (map_libs) { + for (auto lib : *map_libs) + mapEquivCells(lib, hash_matches); + } + hash_matches.deleteContents(); } -static void -findEquivCells1(const LibertyLibrary *library, - LibertyCellSet &cell_equivs) +EquivCells::~EquivCells() +{ + for (auto cell : unique_equiv_cells_) + delete equiv_cells_.findKey(cell); +} + +LibertyCellSeq * +EquivCells::equivs(LibertyCell *cell) +{ + return equiv_cells_.findKey(cell); +} + +// Use a comprehensive hash on cell properties to segregate +// cells into groups of potential matches. +void +EquivCells::findEquivCells(const LibertyLibrary *library, + LibertyCellHashMap &hash_matches) { - LibertyCellHashMap cell_hash; LibertyCellIterator cell_iter(library); while (cell_iter.hasNext()) { LibertyCell *cell = cell_iter.next(); - if (!cell->dontUse()) { + if (!cell->dontUse() + && !stringBeginEqual(cell->name(), "DLY")) { unsigned hash = hashCell(cell); - // Use a comprehensive hash on cell properties to segregate - // cells into groups of potential matches. - LibertyCellSeq *matches = cell_hash[hash]; + LibertyCellSeq *matches = hash_matches.findKey(hash); if (matches) { LibertyCellSeq::Iterator match_iter(matches); while (match_iter.hasNext()) { LibertyCell *match = match_iter.next(); if (equivCells(match, cell)) { - LibertyCellSeq *equivs = match->equivCellsRaw(); + LibertyCellSeq *equivs = equiv_cells_.findKey(match); if (equivs == nullptr) { equivs = new LibertyCellSeq; equivs->push_back(match); - match->setEquivCells(equivs); - cell_equivs.insert(match); + unique_equiv_cells_.push_back(match); + equiv_cells_[match] = equivs; } equivs->push_back(cell); - cell->setEquivCells(equivs); + equiv_cells_[cell] = equivs; + break; + } + } + matches->push_back(cell); + } + else { + matches = new LibertyCellSeq; + hash_matches[hash] = matches; + matches->push_back(cell); + } + } + } +} + +// Map library cells to equiv cells. +void +EquivCells::mapEquivCells(const LibertyLibrary *library, + LibertyCellHashMap &hash_matches) +{ + + LibertyCellIterator cell_iter(library); + while (cell_iter.hasNext()) { + LibertyCell *cell = cell_iter.next(); + if (!cell->dontUse()) { + unsigned hash = hashCell(cell); + LibertyCellSeq *matches = hash_matches.findKey(hash); + if (matches) { + LibertyCellSeq::Iterator match_iter(matches); + while (match_iter.hasNext()) { + LibertyCell *match = match_iter.next(); + if (equivCells(match, cell)) { + LibertyCellSeq *equivs = equiv_cells_.findKey(match); + equiv_cells_[cell] = equivs; break; } } } - else { - matches = new LibertyCellSeq; - cell_hash[hash] = matches; - } - matches->push_back(cell); - } - } - cell_hash.deleteContents(); -} - -struct CellDriveResistanceLess -{ - bool operator()(const LibertyCell *cell1, - const LibertyCell *cell2) const - { - return cellDriveResistance(cell1) > cellDriveResistance(cell2); - } -}; - -static float -cellDriveResistance(const LibertyCell *cell) -{ - return max(cell->driveResistance(TransRiseFall::rise()), - cell->driveResistance(TransRiseFall::fall())); -} - -static void -sortCellEquivs(LibertyCellSet &cell_equivs) -{ - for (auto equiv : cell_equivs) { - LibertyCellSeq *equivs = equiv->equivCells(); - sort(equivs, CellDriveResistanceLess()); - LibertyCell *lower = nullptr; - LibertyCellSeq::Iterator cell_iter(equivs); - while (cell_iter.hasNext()) { - LibertyCell *cell = cell_iter.next(); - if (lower) { - lower->setHigherDrive(cell); - cell->setLowerDrive(lower); - } - lower = cell; } } } @@ -273,7 +280,7 @@ equivCellPorts(const LibertyCell *cell1, } } -static bool +bool equivCellSequentials(const LibertyCell *cell1, const LibertyCell *cell2) { diff --git a/liberty/EquivCells.hh b/liberty/EquivCells.hh index 39cf8a75..c262c807 100644 --- a/liberty/EquivCells.hh +++ b/liberty/EquivCells.hh @@ -17,15 +17,37 @@ #ifndef STA_EQUIV_CELLS_H #define STA_EQUIV_CELLS_H +#include "Vector.hh" #include "Map.hh" +#include "UnorderedMap.hh" #include "LibertyClass.hh" namespace sta { -// Find equivalent cells, sort by drive strength and -// and set cell->equivCells/higherDrive/lowerDrive. -void -findEquivCells(const LibertyLibrary *library); +typedef Map EquivCellMap; +typedef UnorderedMap LibertyCellHashMap; + +class EquivCells +{ +public: + // Find equivalent cells in equiv_libs. + // Optionally add mappings for cells in map_libs. + EquivCells(LibertyLibrarySeq *equiv_libs, + LibertyLibrarySeq *map_libs); + ~EquivCells(); + // Find equivalents for cell (member of from_libs) in to_libs. + LibertyCellSeq *equivs(LibertyCell *cell); + +protected: + void findEquivCells(const LibertyLibrary *library, + LibertyCellHashMap &hash_matches); + void mapEquivCells(const LibertyLibrary *library, + LibertyCellHashMap &hash_matches); + + EquivCellMap equiv_cells_; + // Unique cell for each equiv cell group. + LibertyCellSeq unique_equiv_cells_; +}; // Predicate that is true when the ports, functions, sequentials and // timing arcs match. @@ -48,5 +70,9 @@ bool equivCellTimingArcSets(const LibertyCell *cell1, const LibertyCell *cell2); +bool +equivCellSequentials(const LibertyCell *cell1, + const LibertyCell *cell2); + } // namespace #endif diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index a0ca2def..7af31937 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -84,7 +84,6 @@ LibertyLibrary::LibertyLibrary(const char *name, default_operating_conditions_(nullptr), ocv_arc_depth_(0.0), default_ocv_derate_(nullptr), - found_equiv_cells_(false), buffers_(nullptr) { // Scalar templates are builtin. @@ -153,15 +152,6 @@ LibertyLibrary::findLibertyCellsMatching(PatternMatch *pattern, } } -void -LibertyLibrary::ensureEquivCells() -{ - if (!found_equiv_cells_) { - findEquivCells(this); - found_equiv_cells_ = true; - } -} - LibertyCellSeq * LibertyLibrary::buffers() { @@ -866,10 +856,7 @@ LibertyCell::LibertyCell(LibertyLibrary *library, ocv_derate_(nullptr), is_disabled_constraint_(false), leakage_power_(0.0), - leakage_power_exists_(false), - equiv_cells_(nullptr), - higher_drive_(nullptr), - lower_drive_(nullptr) + leakage_power_exists_(false) { liberty_cell_ = this; } @@ -885,16 +872,6 @@ LibertyCell::~LibertyCell() timing_arc_set_from_map_.deleteContents(); timing_arc_set_to_map_.deleteContents(); - if (equiv_cells_) { - // Carefull because loop below nulls equiv_cells_. - auto equiv_cells = equiv_cells_; - // equiv_cells_ is shared by all of the equivalent cells, so - // delete it once for all of them and null the others. - for (auto equiv : *equiv_cells_) - equiv->setEquivCells(nullptr); - delete equiv_cells; - } - deleteInternalPowerAttrs(); internal_powers_.deleteContents(); leakage_powers_.deleteContents(); @@ -1463,20 +1440,6 @@ LibertyCell::setCornerCell(LibertyCell *corner_cell, //////////////////////////////////////////////////////////////// -LibertyCellSeq * -LibertyCell::equivCells() -{ - if (equiv_cells_ == nullptr) - liberty_library_->ensureEquivCells(); - return equiv_cells_; -} - -void -LibertyCell::setEquivCells(LibertyCellSeq *equiv_cells) -{ - equiv_cells_ = equiv_cells; -} - // Use the worst "drive" for all the timing arcs in the cell. float LibertyCell::driveResistance(const TransRiseFall *tr) const @@ -1489,7 +1452,8 @@ LibertyCell::driveResistance(const TransRiseFall *tr) const TimingArcSetArcIterator arc_iter(set); while (arc_iter.hasNext()) { TimingArc *arc = arc_iter.next(); - if (arc->toTrans()->asRiseFall() == tr) { + if (tr == nullptr + || arc->toTrans()->asRiseFall() == tr) { GateTimingModel *model = dynamic_cast(arc->model()); if (model) { float drive = model->driveResistance(this, nullptr); @@ -1503,30 +1467,10 @@ LibertyCell::driveResistance(const TransRiseFall *tr) const return max_drive; } -LibertyCell * -LibertyCell::higherDrive() const +float +LibertyCell::driveResistance() const { - liberty_library_->ensureEquivCells(); - return higher_drive_; -} - -LibertyCell * -LibertyCell::lowerDrive() const -{ - liberty_library_->ensureEquivCells(); - return lower_drive_; -} - -void -LibertyCell::setHigherDrive(LibertyCell *cell) -{ - higher_drive_ = cell; -} - -void -LibertyCell::setLowerDrive(LibertyCell *cell) -{ - lower_drive_ = cell; + return driveResistance(nullptr); } //////////////////////////////////////////////////////////////// diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index f1809fc1..c5f9df35 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -289,7 +289,6 @@ protected: const TableModel *model, float in_slew, float wire_delay) const; - void ensureEquivCells(); Units *units_; DelayModelType delay_model_type_; @@ -330,7 +329,6 @@ protected: OcvDerate *default_ocv_derate_; OcvDerateMap ocv_derate_map_; SupplyVoltageMap supply_voltage_map_; - bool found_equiv_cells_; LibertyCellSeq *buffers_; // Set if any library has rise/fall capacitances. @@ -492,13 +490,9 @@ public: virtual void finish(bool infer_latches, Report *report, Debug *debug); - LibertyCellSeq *equivCells(); - // Internal. - LibertyCellSeq *equivCellsRaw() { return equiv_cells_; } - void setEquivCells(LibertyCellSeq *equiv_cells); float driveResistance(const TransRiseFall *tr) const; - void setHigherDrive(LibertyCell *cell); - void setLowerDrive(LibertyCell *cell); + // Max of rise/fall. + float driveResistance() const; bool isBuffer() const; // Only valid when isBuffer() returns true. void bufferPorts(// Return values. @@ -569,10 +563,6 @@ protected: float leakage_power_; bool leakage_power_exists_; LibertyPgPortMap pg_port_map_; - LibertyCellSeq *equiv_cells_; - // Next higher/lower drive equivalent cells. - LibertyCell *higher_drive_; - LibertyCell *lower_drive_; private: DISALLOW_COPY_AND_ASSIGN(LibertyCell); diff --git a/liberty/LibertyClass.hh b/liberty/LibertyClass.hh index 3a44c670..12c3941d 100644 --- a/liberty/LibertyClass.hh +++ b/liberty/LibertyClass.hh @@ -57,6 +57,7 @@ class TransRiseFall; class TransRiseFallBoth; class LibertyCellSequentialIterator; +typedef Vector LibertyLibrarySeq; typedef Vector LibertyCellSeq; typedef Vector SequentialSeq; typedef Map LibertyCellEquivMap; diff --git a/search/Property.cc b/search/Property.cc index 42277efb..6590baa6 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -531,10 +531,6 @@ getProperty(const LibertyCell *cell, return PropertyValue(cell->driveResistance(TransRiseFall::rise())); else if (stringEqual(property, "drive_resistance_fall")) return PropertyValue(cell->driveResistance(TransRiseFall::fall())); - else if (stringEqual(property, "higher_drive")) - return PropertyValue(cell->higherDrive()); - else if (stringEqual(property, "lower_drive")) - return PropertyValue(cell->lowerDrive()); else if (stringEqual(property, "is_buffer")) return PropertyValue(cell->isBuffer()); else if (stringEqual(property, "dont_use")) diff --git a/search/Sta.cc b/search/Sta.cc index 68231b85..fa1bab94 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -276,7 +276,8 @@ Sta::Sta() : report_path_(nullptr), power_(nullptr), link_make_black_boxes_(true), - update_genclks_(false) + update_genclks_(false), + equiv_cells_(nullptr) { } @@ -517,6 +518,7 @@ Sta::~Sta() delete units_; delete report_; delete power_; + delete equiv_cells_; } void @@ -3644,7 +3646,7 @@ Sta::replaceCell(Instance *inst, { NetworkEdit *network = networkCmdEdit(); LibertyCell *from_lib_cell = network->libertyCell(inst); - if (equivCells(from_lib_cell, to_lib_cell)) { + if (sta::equivCells(from_lib_cell, to_lib_cell)) { replaceEquivCellBefore(inst, to_lib_cell); network->replaceCell(inst, to_cell); replaceEquivCellAfter(inst); @@ -4966,6 +4968,24 @@ Sta::reportCheck(MaxSkewCheck *check, //////////////////////////////////////////////////////////////// +void +Sta::makeEquivCells(LibertyLibrarySeq *equiv_libs, + LibertyLibrarySeq *map_libs) +{ + delete equiv_cells_; + equiv_cells_ = new EquivCells(equiv_libs, map_libs); +} + +LibertyCellSeq * +Sta::equivCells(LibertyCell *cell) +{ + if (equiv_cells_) + return equiv_cells_->equivs(cell); + else + return nullptr; +} + +//////////////////////////////////////////////////////////////// void Sta::powerPreamble() { diff --git a/search/Sta.hh b/search/Sta.hh index 3b275ecb..394e96bc 100644 --- a/search/Sta.hh +++ b/search/Sta.hh @@ -58,6 +58,7 @@ class ReportField; class Power; class PowerResult; class ClockIterator; +class EquivCells; typedef InstanceSeq::Iterator SlowDrvrIterator; typedef Vector CheckError; @@ -1182,6 +1183,12 @@ public: // Return values. PowerResult &result); + // Find equivalent cells in equiv_libs. + // Optionally add mappings for cells in map_libs. + void makeEquivCells(LibertyLibrarySeq *equiv_libs, + LibertyLibrarySeq *map_libs); + LibertyCellSeq *equivCells(LibertyCell *cell); + protected: // Default constructors that are called by makeComponents in the Sta // constructor. These can be redefined by a derived class to @@ -1311,6 +1318,7 @@ protected: Tcl_Interp *tcl_interp_; bool link_make_black_boxes_; bool update_genclks_; + EquivCells *equiv_cells_; // Singleton sta used by tcl command interpreter. static Sta *sta_; diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 6bfd8935..5b463b8a 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -50,8 +50,8 @@ #include "Transition.hh" #include "TimingRole.hh" #include "TimingArc.hh" -#include "EquivCells.hh" #include "Liberty.hh" +#include "EquivCells.hh" #include "Network.hh" #include "Clock.hh" #include "PortDelay.hh" @@ -2279,19 +2279,41 @@ find_library_buffers(LibertyLibrary *library) return library->buffers(); } -LibertyCellSeq * -equiv_cells(LibertyCell *cell) +void +make_equiv_cells(LibertyLibrary *lib) { - return cell->equivCells(); + LibertyLibrarySeq libs; + libs.push_back(lib); + Sta::sta()->makeEquivCells(&libs, nullptr); +} + +LibertyCellSeq * +find_equiv_cells(LibertyCell *cell) +{ + return Sta::sta()->equivCells(cell); +} + +bool +equiv_cells(LibertyCell *cell1, + LibertyCell *cell2) +{ + return sta::equivCells(cell1, cell2); } bool equiv_cell_ports(LibertyCell *cell1, - LibertyCell *cell2) + LibertyCell *cell2) { return equivCellPorts(cell1, cell2); } +bool +equiv_cell_timing_arcs(LibertyCell *cell1, + LibertyCell *cell2) +{ + return equivCellTimingArcSets(cell1, cell2); +} + void set_cmd_namespace_cmd(const char *namespc) {