diff --git a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp index f970eb6ea..dea035853 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp @@ -30,6 +30,8 @@ inline void post_layout_optimization(pybind11::module& m) DOC(fiction_post_layout_optimization_params_max_gate_relocations)) .def_readwrite("optimize_pos_only", &fiction::post_layout_optimization_params::optimize_pos_only, DOC(fiction_post_layout_optimization_params_optimize_pos_only)) + .def_readwrite("planar_optimization", &fiction::post_layout_optimization_params::planar_optimization, + DOC(fiction_post_layout_optimization_params_planar_optimization)) ; diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index ea968c95b..94b6c4e09 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5442,6 +5442,10 @@ Parameter ``start``: Parameter ``end``: The ending coordinate of the path. +Parameter ``planar_optimization``: + Only allow relocation if a crossing-free wiring can be found. + Defaults to false. + Returns: The computed path as a sequence of coordinates in the layout.)doc"; @@ -5778,6 +5782,10 @@ Parameter ``lyt``: Parameter ``old_pos``: Old position of the gate to be moved. +Parameter ``planar_optimization``: + Only allow relocation if a crossing-free wiring can be found. + Defaults to false. + Returns: `true` if the gate was moved successfully, `false` otherwise.)doc"; @@ -13627,6 +13635,11 @@ number of tiles in the given layout if not specified.)doc"; static const char *__doc_fiction_post_layout_optimization_params_optimize_pos_only = R"doc(Only optimize PO positions.)doc"; +static const char *__doc_fiction_post_layout_optimization_params_planar_optimization = +R"doc(Disable the creation of crossings during optimization. If set to true, +gates will only be relocated if a crossing-free wiring is found. +Defaults to false.)doc"; + static const char *__doc_fiction_post_layout_optimization_stats = R"doc(This struct stores statistics about the post-layout optimization process.)doc"; diff --git a/cli/cmd/physical_design/optimize.hpp b/cli/cmd/physical_design/optimize.hpp index 4439f376d..1c464f1f9 100644 --- a/cli/cmd/physical_design/optimize.hpp +++ b/cli/cmd/physical_design/optimize.hpp @@ -44,6 +44,10 @@ class optimize_command : public command add_option("--max_gate_relocations,-m", max_gate_relocations, "Specify the maximum number of relocations to try for each gate (defaults " "to the number of tiles in the layout)."); + add_flag("--planar_optimization,-p", ps.planar_optimization, + "During optimization, only relocate gates if the new wiring contains no crossings. For planar " + "layouts, the resulting layout will also be planar. If the layout already contains crossings, the " + "optimized layout will have the same number of crossings or less."); add_flag("--verbose,-v", "Be verbose"); } diff --git a/include/fiction/algorithms/physical_design/post_layout_optimization.hpp b/include/fiction/algorithms/physical_design/post_layout_optimization.hpp index bb49bf4a4..fbcec43c6 100644 --- a/include/fiction/algorithms/physical_design/post_layout_optimization.hpp +++ b/include/fiction/algorithms/physical_design/post_layout_optimization.hpp @@ -47,6 +47,11 @@ struct post_layout_optimization_params * Only optimize PO positions. */ bool optimize_pos_only = false; + /** + * Disable the creation of crossings during optimization. If set to true, gates will only be relocated if a + * crossing-free wiring is found. Defaults to false. + */ + bool planar_optimization = false; }; /** @@ -376,17 +381,20 @@ template * @param lyt Reference to the layout. * @param start The starting coordinate of the path. * @param end The ending coordinate of the path. + * @param planar_optimization Only allow relocation if a crossing-free wiring can be found. Defaults to false. * @return The computed path as a sequence of coordinates in the layout. */ template -layout_coordinate_path get_path_and_obstruct(Lyt& lyt, const tile& start, const tile& end) +layout_coordinate_path get_path_and_obstruct(Lyt& lyt, const tile& start, const tile& end, + const bool planar_optimization = false) { static_assert(is_gate_level_layout_v, "Lyt is not a gate-level layout"); static_assert(is_cartesian_layout_v, "Lyt is not a Cartesian layout"); using dist = twoddwave_distance_functor; using cost = unit_cost_functor; - static const a_star_params params{true}; + static a_star_params params{}; + params.crossings = !planar_optimization; layout_coordinate_path path = a_star>(lyt, {start, end}, dist(), cost(), params); @@ -412,11 +420,12 @@ layout_coordinate_path get_path_and_obstruct(Lyt& lyt, const tile& sta * @tparam Lyt Cartesian obstruction gate-level layout type. * @param lyt 2DDWave-clocked cartesian obstruction gate-level layout. * @param old_pos Old position of the gate to be moved. + * @param planar_optimization Only allow relocation if a crossing-free wiring can be found. Defaults to false. * @return `true` if the gate was moved successfully, `false` otherwise. */ template bool improve_gate_location(Lyt& lyt, const tile& old_pos, const tile& max_non_po, - const uint64_t max_gate_relocations) noexcept + const uint64_t max_gate_relocations, const bool planar_optimization = false) noexcept { static_assert(is_gate_level_layout_v, "Lyt is not a gate-level layout"); static_assert(is_cartesian_layout_v, "Lyt is not a Cartesian layout"); @@ -546,22 +555,26 @@ bool improve_gate_location(Lyt& lyt, const tile& old_pos, const tile& // 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); + new_path_from_fanin_1_to_gate = + get_path_and_obstruct(lyt, fanins[0], new_pos, planar_optimization); } if (fanins.size() == 2) { - new_path_from_fanin_2_to_gate = get_path_and_obstruct(lyt, fanins[1], new_pos); + new_path_from_fanin_2_to_gate = + get_path_and_obstruct(lyt, fanins[1], new_pos, planar_optimization); } if (!fanouts.empty()) { - new_path_from_gate_to_fanout_1 = get_path_and_obstruct(lyt, new_pos, fanouts[0]); + new_path_from_gate_to_fanout_1 = + get_path_and_obstruct(lyt, new_pos, fanouts[0], planar_optimization); } if (fanouts.size() == 2) { - new_path_from_gate_to_fanout_2 = get_path_and_obstruct(lyt, new_pos, fanouts[1]); + new_path_from_gate_to_fanout_2 = + get_path_and_obstruct(lyt, new_pos, fanouts[1], planar_optimization); } // if possible routing was found, it will be applied @@ -955,7 +968,8 @@ class post_layout_optimization_impl { if (!ps.optimize_pos_only || (ps.optimize_pos_only && layout.is_po_tile(gate_tile))) { - if (detail::improve_gate_location(layout, gate_tile, max_non_po, max_gate_relocations)) + if (detail::improve_gate_location(layout, gate_tile, max_non_po, max_gate_relocations, + ps.planar_optimization)) { moved_at_least_one_gate = true; } diff --git a/test/algorithms/physical_design/post_layout_optimization.cpp b/test/algorithms/physical_design/post_layout_optimization.cpp index 96795c46c..d2836b0fb 100644 --- a/test/algorithms/physical_design/post_layout_optimization.cpp +++ b/test/algorithms/physical_design/post_layout_optimization.cpp @@ -106,7 +106,7 @@ TEST_CASE("Layout equivalence", "[post_layout_optimization]") check_layout_equiv_all(); } - SECTION("Corner Cases") + SECTION("Corner cases") { using gate_layout = gate_level_layout>>>; @@ -127,7 +127,7 @@ TEST_CASE("Layout equivalence", "[post_layout_optimization]") } } - SECTION("Maximum Gate Relocations") + SECTION("Maximum gate relocations") { using gate_layout = gate_level_layout>>>; @@ -157,6 +157,39 @@ TEST_CASE("Layout equivalence", "[post_layout_optimization]") check_eq(blueprints::mux21_network(), layout); } + + SECTION("Planar optimization with planar layout") + { + using gate_layout = gate_level_layout>>>; + + const auto layout = blueprints::planar_unoptimized_layout(); + + post_layout_optimization_stats stats{}; + post_layout_optimization_params params{}; + params.planar_optimization = true; + post_layout_optimization(layout, params, &stats); + + check_eq(blueprints::planar_unoptimized_layout(), layout); + CHECK(layout.z() == 0); + } + + SECTION("Planar optimization with crossing layout") + { + using gate_layout = gate_level_layout>>>; + + const auto layout = blueprints::planar_optimization_layout(); + + post_layout_optimization_stats stats{}; + post_layout_optimization_params params{}; + + params.planar_optimization = true; + post_layout_optimization(layout, params, &stats); + CHECK(!layout.is_inv(layout.get_node({1, 0}))); + + params.planar_optimization = false; + post_layout_optimization(layout, params, &stats); + CHECK(layout.is_inv(layout.get_node({1, 0}))); + } } TEST_CASE("Optimization steps", "[post_layout_optimization]") diff --git a/test/utils/blueprints/layout_blueprints.hpp b/test/utils/blueprints/layout_blueprints.hpp index d4a2bb070..ed8f90633 100644 --- a/test/utils/blueprints/layout_blueprints.hpp +++ b/test/utils/blueprints/layout_blueprints.hpp @@ -535,6 +535,47 @@ GateLyt optimization_layout_corner_case_outputs_2() noexcept return layout; } +template +GateLyt planar_unoptimized_layout() noexcept +{ + GateLyt layout{{4, 4, 0}, fiction::twoddwave_clocking()}; + + const auto x1 = layout.create_pi("x1", {2, 0}); + const auto x2 = layout.create_pi("x2", {0, 2}); + + const auto w1 = layout.create_buf(x1, {2, 1}); + const auto w2 = layout.create_buf(x2, {1, 2}); + const auto and1 = layout.create_and(w1, w2, {2, 2}); + const auto w3 = layout.create_buf(and1, {3, 2}); + const auto not2 = layout.create_not(w3, {4, 2}); + const auto w4 = layout.create_buf(not2, {4, 3}); + + layout.create_po(w4, "f1", {4, 4}); + + return layout; +} + +template +GateLyt planar_optimization_layout() noexcept +{ + GateLyt layout{{2, 2, 1}, fiction::twoddwave_clocking()}; + + const auto x1 = layout.create_pi("x1", {0, 0}); + const auto x2 = layout.create_pi("x2", {0, 1}); + layout.create_pi("x3", {0, 2}); + layout.create_pi("x4", {2, 0}); + + const auto w1 = layout.create_buf(x1, {1, 0}); + const auto w2 = layout.create_buf(x2, {1, 1}); + const auto w3 = layout.create_buf(w1, {1, 1, 1}); + const auto not1 = layout.create_not(w3, {1, 2}); + + layout.create_po(w2, "f1", {2, 1}); + layout.create_po(not1, "f2", {2, 2}); + + return layout; +} + template CellLyt single_layer_qca_and_gate() noexcept {