Skip to content

Commit

Permalink
🐛 Fixed multiple post_layout_optimization bugs (#472)
Browse files Browse the repository at this point in the history
* Update post_layout_optimization.hpp

* Update wiring_reduction.hpp

* Update include/fiction/algorithms/physical_design/post_layout_optimization.hpp

Co-authored-by: Marcel Walter <[email protected]>
Signed-off-by: simon1hofmann <[email protected]>

* Update wiring_reduction.hpp

* 🎨 Incorporated pre-commit fixes

* Update post_layout_optimization.hpp

* Update wiring_reduction.hpp

* Update post_layout_optimization.hpp

* Update test_post_layout_optimization.py

* Update post_layout_optimization.hpp

* 🎨 Incorporated pre-commit fixes

* Update test_post_layout_optimization.py

* Update post_layout_optimization.hpp

* Update wiring_reduction.hpp

* Update post_layout_optimization.hpp

* Update wiring_reduction.hpp

* Update post_layout_optimization.hpp

* Update pyfiction-docstring-generator.yml

---------

Signed-off-by: simon1hofmann <[email protected]>
Co-authored-by: Marcel Walter <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 18, 2024
1 parent c6034ee commit 222a86d
Show file tree
Hide file tree
Showing 2 changed files with 279 additions and 158 deletions.
136 changes: 113 additions & 23 deletions include/fiction/algorithms/physical_design/post_layout_optimization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,22 +279,22 @@ template <typename Lyt>
if (fanins_set.find(fanin) == fanins_set.cend())
{

// Add fanin to the respective route
// add fanin to the respective route
add_fanin_to_route(op, fanins_set.empty(), ffd);
add_fanin_to_route(fanin, fanins_set.empty(), ffd);

// Continue until gate or primary input (PI) is found
// continue until gate or primary input (PI) is found
while (lyt.is_wire_tile(fanin) && lyt.fanout_size(lyt.get_node(fanin)) == 1 &&
!lyt.is_pi_tile(fanin))
{
ffd.to_clear.push_back(fanin);
fanin = lyt.incoming_data_flow(fanin).front();

// Add fanin to the respective route
// add fanin to the respective route
add_fanin_to_route(fanin, fanins_set.empty(), ffd);
}

// Set the respective fanin based on the route
// set the respective fanin based on the route
if (fanins_set.empty())
{
fanin1 = fanin;
Expand All @@ -316,22 +316,22 @@ template <typename Lyt>
if (fanouts_set.find(fanout) == fanouts_set.cend())
{

// Add fanout to the respective route
// add fanout to the respective route
add_fanout_to_route(op, fanouts_set.empty(), ffd);
add_fanout_to_route(fanout, fanouts_set.empty(), ffd);

// Continue until gate or primary output (PO) is found
// continue until gate or primary output (PO) is found
while (lyt.is_wire_tile(fanout) && lyt.fanout_size(lyt.get_node(fanout)) != 0 &&
lyt.fanout_size(lyt.get_node(fanout)) != 2)
{
ffd.to_clear.push_back(fanout);
fanout = lyt.outgoing_data_flow(fanout).front();

// Add fanout to the respective route
// add fanout to the respective route
add_fanout_to_route(fanout, fanouts_set.empty(), ffd);
}

// Set the respective fanout based on the route
// set the respective fanout based on the route
if (fanouts_set.empty())
{
fanout1 = fanout;
Expand Down Expand Up @@ -387,7 +387,7 @@ layout_coordinate_path<Lyt> get_path_and_obstruct(Lyt& lyt, const tile<Lyt>& sta

layout_coordinate_path<Lyt> path = a_star<layout_coordinate_path<Lyt>>(lyt, {start, end}, dist(), cost(), params);

// Obstruct the tiles along the computed path.
// obstruct the tiles along the computed path.
for (const auto& tile : path)
{
lyt.obstruct_coordinate(tile);
Expand Down Expand Up @@ -514,7 +514,7 @@ bool improve_gate_location(Lyt& lyt, const tile<Lyt>& old_pos, const tile<Lyt>&
{
const uint64_t y = k - x;

if (moved_gate || (num_gate_relocations >= max_gate_relocations))
if (moved_gate || ((num_gate_relocations >= max_gate_relocations) && !lyt.is_po_tile(current_pos)))
{
break;
}
Expand All @@ -523,7 +523,7 @@ bool improve_gate_location(Lyt& lyt, const tile<Lyt>& old_pos, const tile<Lyt>&
if (lyt.y() >= y && y >= min_y && lyt.x() >= x && x >= min_x && ((x + y) <= max_diagonal) &&
(((x + y) < max_diagonal) || (y <= max_y)) &&
((!lyt.is_pi_tile(current_pos)) || (lyt.is_pi_tile(current_pos) && (x == 0 || y == 0))) &&
!(lyt.is_po_tile(current_pos) && (((x <= max_non_po.x) && (y <= max_non_po.y)) ||
!(lyt.is_po_tile(current_pos) && (((x < max_non_po.x) && (y < max_non_po.y)) ||
((x + y) == static_cast<uint64_t>(old_pos.x + old_pos.y)))))
{
new_pos = tile<Lyt>{x, y};
Expand All @@ -540,7 +540,7 @@ bool improve_gate_location(Lyt& lyt, const tile<Lyt>& old_pos, const tile<Lyt>&
// get paths for fanins and fanouts
layout_coordinate_path<Lyt> new_path_from_fanin_1_to_gate, new_path_from_fanin_2_to_gate,
new_path_from_gate_to_fanout_1, new_path_from_gate_to_fanout_2;
// Get paths for fanins and fanouts
// get paths for fanins and fanouts
if (!fanins.empty())
{
new_path_from_fanin_1_to_gate = get_path_and_obstruct(lyt, fanins[0], new_pos);
Expand Down Expand Up @@ -636,7 +636,7 @@ bool improve_gate_location(Lyt& lyt, const tile<Lyt>& old_pos, const tile<Lyt>&
}
}

if (moved_gate || (num_gate_relocations >= max_gate_relocations))
if (moved_gate || ((num_gate_relocations >= max_gate_relocations) && !lyt.is_po_tile(current_pos)))
{
break;
}
Expand Down Expand Up @@ -763,6 +763,97 @@ void optimize_output_positions(Lyt& lyt) noexcept
}
}
}
// calculate bounding box
auto bounding_box = bounding_box_2d(lyt);
lyt.resize({bounding_box.get_max().x, bounding_box.get_max().y, lyt.z()});

// check for misplaced POs in second last row and move them one row down
for (uint64_t x = 0; x < lyt.x(); ++x)
{
if (lyt.is_po_tile({x, lyt.y() - 1, 0}))
{
// get fanin signal of the PO
std::vector<mockturtle::signal<Lyt>> signals{};
signals.reserve(lyt.fanin_size(lyt.get_node({x, lyt.y()})));
lyt.foreach_fanin(lyt.get_node({x, lyt.y() - 1}),
[&signals](const auto& fanin) { signals.push_back(fanin); });

// move PO one row down
lyt.move_node(lyt.get_node({x, lyt.y() - 1}), {x, lyt.y(), 0}, {});

// create a wire segment at the previous location of the PO and connect it with its fanin
lyt.create_buf(signals[0], {x, lyt.y() - 1});

// connect the PO with the new wire segment
lyt.move_node(lyt.get_node({x, lyt.y()}), {x, lyt.y(), 0},
{lyt.make_signal(lyt.get_node({x, lyt.y() - 1}))});
}
}

// check for misplaced POs in second last column and move them one column to the right
for (uint64_t y = 0; y < lyt.y(); ++y)
{
if (lyt.is_po_tile({lyt.x() - 1, y, 0}))
{
// get fanin signal of the PO
std::vector<mockturtle::signal<Lyt>> signals{};
signals.reserve(lyt.fanin_size(lyt.get_node({lyt.x(), y})));
lyt.foreach_fanin(lyt.get_node({lyt.x() - 1, y}),
[&signals](const auto& fanin) { signals.push_back(fanin); });

// move PO one column to the right
lyt.move_node(lyt.get_node({lyt.x() - 1, y}), {lyt.x(), y, 0}, {});

// create a wire segment at the previous location of the PO and connect it with its fanin
lyt.create_buf(signals[0], {lyt.x() - 1, y});

// connect the PO with the new wire segment
lyt.move_node(lyt.get_node({lyt.x(), y}), {lyt.x(), y, 0},
{lyt.make_signal(lyt.get_node({lyt.x() - 1, y}))});
}
}

// update bounding box
bounding_box.update_bounding_box();
lyt.resize({bounding_box.get_max().x, bounding_box.get_max().y, lyt.z()});

// check if PO is located in bottom right corner and relocation would save more tiles (only possible for layouts
// with a single PO)
if (lyt.is_po_tile({lyt.x(), lyt.y(), 0}) && (lyt.num_pos() == 1))
{
// check if relocation would save tiles
if (lyt.has_western_incoming_signal({lyt.x(), lyt.y(), 0}) &&
((lyt.x() * (lyt.y() + 2)) < ((lyt.x() + 1) * (lyt.y() + 1))))
{
// get fanin signal of the PO
std::vector<mockturtle::signal<Lyt>> signals{};
signals.reserve(lyt.fanin_size(lyt.get_node({lyt.x(), lyt.y()})));
lyt.foreach_fanin(lyt.get_node({lyt.x(), lyt.y()}),
[&signals](const auto& fanin) { signals.push_back(fanin); });

// resize layout
lyt.resize({lyt.x(), lyt.y() + 1, lyt.z()});

// move PO one tile down and to the left
lyt.move_node(lyt.get_node({lyt.x(), lyt.y() - 1}), {lyt.x() - 1, lyt.y(), 0}, signals);
}
// check if relocation would save tiles
else if (lyt.has_northern_incoming_signal({lyt.x(), lyt.y(), 0}) &&
(((lyt.x() + 2) * lyt.y()) < ((lyt.x() + 1) * (lyt.y() + 1))))
{
// get fanin signal of the PO
std::vector<mockturtle::signal<Lyt>> signals{};
signals.reserve(lyt.fanin_size(lyt.get_node({lyt.x(), lyt.y()})));
lyt.foreach_fanin(lyt.get_node({lyt.x(), lyt.y()}),
[&signals](const auto& fanin) { signals.push_back(fanin); });

// resize layout
lyt.resize({lyt.x() + 1, lyt.y(), lyt.z()});

// move PO one tile up and to the right
lyt.move_node(lyt.get_node({lyt.x() - 1, lyt.y()}), {lyt.x(), lyt.y() - 1, 0}, signals);
}
}
}
/**
* Custom comparison function for sorting tiles based on the sum of their coordinates that breaks ties based on the
Expand Down Expand Up @@ -804,7 +895,7 @@ class post_layout_optimization_impl

uint64_t max_gate_relocations = ps.max_gate_relocations.value_or((plyt.x() + 1) * (plyt.y() + 1));

// Optimization
// optimization
auto layout = obstruction_layout<Lyt>(plyt);
bool moved_at_least_one_gate = true;
bool reduced_wiring = true;
Expand Down Expand Up @@ -846,15 +937,14 @@ class post_layout_optimization_impl

std::sort(gate_tiles.begin(), gate_tiles.end(), detail::compare_gate_tiles<Lyt>);

tile<Lyt> max_non_po;
// Iterate through the vector in reverse
for (auto it = gate_tiles.rbegin(); it != gate_tiles.rend(); ++it)
tile<Lyt> max_non_po{0, 0};
// determine minimal border for POs
for (const auto& gate_tile : gate_tiles)
{
// Stop if a condition based on the element is met
if (!layout.is_po_tile(*it))
if (!layout.is_po_tile(gate_tile))
{
max_non_po = *it;
break;
max_non_po.x = std::max(max_non_po.x, gate_tile.x);
max_non_po.y = std::max(max_non_po.y, gate_tile.y);
}
}
moved_at_least_one_gate = false;
Expand Down Expand Up @@ -936,14 +1026,14 @@ void post_layout_optimization(const Lyt& lyt, post_layout_optimization_params ps
static_assert(is_gate_level_layout_v<Lyt>, "Lyt is not a gate-level layout");
static_assert(is_cartesian_layout_v<Lyt>, "Lyt is not a Cartesian layout");

// Check if the clocking scheme is 2DDWave
// check if the clocking scheme is 2DDWave
if (!lyt.is_clocking_scheme(clock_name::TWODDWAVE))
{
std::cout << "[e] the given layout has to be 2DDWave-clocked\n";
return;
}

// Initialize stats for runtime measurement
// initialize stats for runtime measurement
post_layout_optimization_stats st{};
detail::post_layout_optimization_impl<Lyt> p{lyt, ps, st};

Expand Down
Loading

0 comments on commit 222a86d

Please sign in to comment.