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)
{