1111#include < optional>
1212#include < sstream>
1313#include < string>
14+ #include < unordered_set>
1415#include < utility>
1516
1617#include " BaseMove.hh"
1718#include " odb/db.h"
1819#include " sta/ArcDelayCalc.hh"
1920#include " sta/Delay.hh"
21+ #include " sta/FuncExpr.hh"
2022#include " sta/Graph.hh"
2123#include " sta/Liberty.hh"
2224#include " sta/MinMax.hh"
@@ -85,7 +87,7 @@ bool SwapPinsMove::doMove(const Path* drvr_path,
8587 // We get the driver port and the cell for that port.
8688 LibertyPort* input_port = network_->libertyPort (in_pin);
8789 LibertyPort* swap_port = input_port;
88- sta::LibertyPortSet ports;
90+ LibertyPortVec ports;
8991
9092 // Skip output to output paths
9193 if (input_port->direction ()->isOutput ()) {
@@ -204,7 +206,7 @@ void SwapPinsMove::swapPins(Instance* inst,
204206// (depending on agreement).
205207void SwapPinsMove::equivCellPins (const LibertyCell* cell,
206208 LibertyPort* input_port,
207- sta::LibertyPortSet & ports)
209+ LibertyPortVec & ports)
208210{
209211 if (cell->hasSequentials () || cell->isIsolationCell ()) {
210212 ports.clear ();
@@ -230,51 +232,59 @@ void SwapPinsMove::equivCellPins(const LibertyCell* cell,
230232 }
231233 }
232234
233- if (outputs >= 1 && inputs >= 2 ) {
234- sta::LibertyCellPortIterator port_iter2 (cell);
235- while (port_iter2.hasNext ()) {
236- LibertyPort* candidate_port = port_iter2.next ();
237- if (!candidate_port->direction ()->isInput ()) {
238- continue ;
239- }
235+ if (outputs < 1 || inputs < 2 ) {
236+ return ;
237+ }
240238
241- sta::LibertyCellPortIterator output_port_iter (cell);
242- std::optional<bool > is_equivalent;
243- // Loop through all the output ports and make sure they are equivalent
244- // under swaps of candidate_port and input_port. For multi-ouput gates
245- // like full adders.
246- while (output_port_iter.hasNext ()) {
247- LibertyPort* output_candidate_port = output_port_iter.next ();
248- sta::FuncExpr* output_expr = output_candidate_port->function ();
249- if (!output_candidate_port->direction ()->isOutput ()) {
250- continue ;
251- }
239+ sta::LibertyCellPortIterator port_iter2 (cell);
240+ std::unordered_set<LibertyPort*> seen_ports;
241+ while (port_iter2.hasNext ()) {
242+ LibertyPort* candidate_port = port_iter2.next ();
243+ if (!candidate_port->direction ()->isInput ()) {
244+ continue ;
245+ }
252246
253- if (output_expr == nullptr ) {
254- continue ;
255- }
247+ sta::LibertyCellPortIterator output_port_iter (cell);
248+ std::optional<bool > is_equivalent;
249+ // Loop through all the output ports and make sure they are equivalent
250+ // under swaps of candidate_port and input_port. For multi-ouput gates
251+ // like full adders.
252+ while (output_port_iter.hasNext ()) {
253+ LibertyPort* output_candidate_port = output_port_iter.next ();
254+ sta::FuncExpr* output_expr = output_candidate_port->function ();
255+ if (!output_candidate_port->direction ()->isOutput ()) {
256+ continue ;
257+ }
256258
257- if (input_port == candidate_port ) {
258- continue ;
259- }
259+ if (output_expr == nullptr ) {
260+ continue ;
261+ }
260262
261- bool is_equivalent_result
262- = isPortEqiv (output_expr, cell, input_port, candidate_port);
263+ if (input_port == candidate_port) {
264+ continue ;
265+ }
263266
264- if (!is_equivalent.has_value ()) {
265- is_equivalent = is_equivalent_result;
266- continue ;
267- }
267+ bool is_equivalent_result
268+ = isPortEqiv (output_expr, cell, input_port, candidate_port);
268269
269- is_equivalent = is_equivalent.value () && is_equivalent_result;
270+ if (!is_equivalent.has_value ()) {
271+ is_equivalent = is_equivalent_result;
272+ continue ;
270273 }
271274
272- // candidate_port is equivalent to input_port under all output ports
273- // of this cell.
274- if (is_equivalent.has_value () && is_equivalent.value ()) {
275- ports.insert (candidate_port);
276- }
275+ is_equivalent = is_equivalent.value () && is_equivalent_result;
277276 }
277+
278+ // candidate_port is equivalent to input_port under all output ports
279+ // of this cell.
280+ if (is_equivalent.has_value () && is_equivalent.value ()
281+ && !seen_ports.contains (candidate_port)) {
282+ seen_ports.insert (candidate_port);
283+ ports.push_back (candidate_port);
284+ }
285+ }
286+ if (!seen_ports.empty ()) { // If we added any ports sort them.
287+ std::ranges::sort (ports, {}, [](auto * p1) { return p1->id (); });
278288 }
279289}
280290
@@ -293,7 +303,7 @@ void SwapPinsMove::reportSwappablePins()
293303 if (!port->direction ()->isInput ()) {
294304 continue ;
295305 }
296- sta::LibertyPortSet ports;
306+ LibertyPortVec ports;
297307 equivCellPins (cell, port, ports);
298308 std::ostringstream ostr;
299309 for (auto port : ports) {
@@ -310,7 +320,7 @@ void SwapPinsMove::reportSwappablePins()
310320// where 2 paths go through the same gate (we could end up swapping pins twice)
311321void SwapPinsMove::findSwapPinCandidate (LibertyPort* input_port,
312322 LibertyPort* drvr_port,
313- const sta::LibertyPortSet & equiv_ports,
323+ const LibertyPortVec & equiv_ports,
314324 float load_cap,
315325 const DcalcAnalysisPt* dcalc_ap,
316326 LibertyPort** swap_port)
@@ -359,18 +369,21 @@ void SwapPinsMove::findSwapPinCandidate(LibertyPort* input_port,
359369 }
360370
361371 for (LibertyPort* port : equiv_ports) {
362- if (port_delays.find (port) == port_delays.end ()) {
363- // It's possible than an equivalent pin doesn't have
364- // a path to the driver.
372+ // Guard Clause:
373+ // 1. Check if port delay exists
374+ // 2. Check if port is NOT an input
375+ // 3. Check if port is equivalent to input_port
376+ // 4. Check if port is equivalent to drvr_port
377+ if (!port_delays.contains (port) || !port->direction ()->isInput ()
378+ || sta::LibertyPort::equiv (input_port, port)
379+ || sta::LibertyPort::equiv (drvr_port, port)) {
365380 continue ;
366381 }
367382
368- if (port->direction ()->isInput ()
369- && !sta::LibertyPort::equiv (input_port, port)
370- && !sta::LibertyPort::equiv (drvr_port, port)
371- && port_delays[port] < base_delay) {
383+ auto port_delay = port_delays[port];
384+ if (port_delay < base_delay) {
372385 *swap_port = port;
373- base_delay = port_delays[port] ;
386+ base_delay = port_delay ;
374387 }
375388 }
376389}
0 commit comments