diff --git a/include/mockturtle/algorithms/lut_mapper.hpp b/include/mockturtle/algorithms/lut_mapper.hpp index 57659041d..5c613d19b 100644 --- a/include/mockturtle/algorithms/lut_mapper.hpp +++ b/include/mockturtle/algorithms/lut_mapper.hpp @@ -231,6 +231,9 @@ class lut_cut_set { *pit++ = &c; } + /* best() exposes the first cut even when the set is empty. */ + _cuts[0].set_leaves( _cuts[0].begin(), _cuts[0].begin() ); + _cuts[0].data() = {}; } /*! \brief Adds a cut to the end of the set. @@ -3012,4 +3015,4 @@ void lut_map_inplace( Ntk& ntk, lut_map_params const& ps = {}, lut_map_stats* ps } } -} /* namespace mockturtle */ \ No newline at end of file +} /* namespace mockturtle */ diff --git a/include/mockturtle/utils/cuts.hpp b/include/mockturtle/utils/cuts.hpp index 5a9c4404f..d15a86237 100644 --- a/include/mockturtle/utils/cuts.hpp +++ b/include/mockturtle/utils/cuts.hpp @@ -502,6 +502,9 @@ void cut_set::clear() { *pit++ = &c; } + /* best() exposes the first cut even when the set is empty. */ + _cuts[0].set_leaves( _cuts[0].begin(), _cuts[0].begin() ); + _cuts[0].data() = {}; } template diff --git a/test/algorithms/lut_mapper.cpp b/test/algorithms/lut_mapper.cpp index 343697385..74cdc666d 100644 --- a/test/algorithms/lut_mapper.cpp +++ b/test/algorithms/lut_mapper.cpp @@ -334,3 +334,66 @@ TEST_CASE( "LUT map remapping LUT network", "[lut_mapper]" ) CHECK( mapped_ntk.num_cells() == 1 ); CHECK( *equivalence_checking( miter_ntk ) == true ); } + +TEST_CASE( "LUT map of an AIG with nodes unreachable from the outputs", "[lut_mapper]" ) +{ + /* `compute_share_mapping_init` calls `best()` on every node index, including + nodes the cut enumerator never visited because no output depends on them. + Their cut set is empty, so `clear()` must initialize the first cut + exposed by `best()`. */ + aig_network aig; + + auto const a = aig.create_pi(); + auto const b = aig.create_pi(); + auto const c = aig.create_pi(); + + auto const f1 = aig.create_and( a, b ); + auto const f2 = aig.create_and( f1, c ); + aig.create_po( f2 ); + + /* dangling: driven by primary inputs, driving no output */ + auto const d1 = aig.create_and( a, !b ); + auto const d2 = aig.create_and( d1, !c ); + auto const d3 = aig.create_and( d2, a ); + aig.create_and( d3, !b ); + + CHECK( aig.num_gates() == 6 ); + + lut_map_params ps; + ps.cut_enumeration_ps.cut_size = 4; + ps.area_oriented_mapping = true; + + const klut_network klut = lut_map( aig, ps ); + + CHECK( klut.num_gates() == 1 ); +} + +TEST_CASE( "empty LUT cut set has an initialized best cut", "[lut_mapper]" ) +{ + using cut_type = cut<16, cut_data>; + detail::lut_cut_set set; + + SECTION( "newly constructed" ) + { + } + + SECTION( "after clearing populated and reordered storage" ) + { + std::vector leaves{ 1, 2, 3 }; + auto& first = set.add_cut( leaves.begin(), leaves.end() ); + first->func_id = 42; + first->data.lut_area = 23; + set.add_cut( leaves.begin(), leaves.begin() + 1 ); + set.update_best( 1 ); + set.clear(); + } + + CHECK( set.size() == 0 ); + CHECK( set.best().size() == 0 ); + CHECK( set.best().signature() == 0 ); + CHECK( set.best().begin() == set.best().end() ); + auto const& best = set.best(); + CHECK( best.begin() == best.end() ); + CHECK( best->func_id == 0 ); + CHECK( best->data.lut_area == 0 ); +} diff --git a/test/utils/cuts.cpp b/test/utils/cuts.cpp index b0c82cf75..f39f64ead 100644 --- a/test/utils/cuts.cpp +++ b/test/utils/cuts.cpp @@ -188,3 +188,28 @@ TEST_CASE( "merge three cuts", "[cuts]" ) ct.merge( c3, cr, 10 ); CHECK( std::vector( cr.begin(), cr.end() ) == std::vector{ 1u, 2u, 3u, 4u, 5u, 6u, 7u, 9u } ); } + +TEST_CASE( "empty cut set has an initialized best cut", "[cuts]" ) +{ + cut_set, 25> set; + + SECTION( "newly constructed" ) + { + } + + SECTION( "after clearing populated and reordered storage" ) + { + std::vector leaves{ 1, 2, 3 }; + set.add_cut( leaves.begin(), leaves.end() ).data() = 42; + set.add_cut( leaves.begin(), leaves.begin() + 1 ).data() = 23; + set.update_best( 1 ); + set.clear(); + } + + CHECK( set.size() == 0 ); + CHECK( set.best().size() == 0 ); + CHECK( set.best().signature() == 0 ); + CHECK( set.best().begin() == set.best().end() ); + CHECK( ( *set.begin() )->begin() == ( *set.begin() )->end() ); + CHECK( set.best().data() == 0 ); +}