Skip to content

Commit 75178f9

Browse files
authored
Window rewriting (#449)
* window_rewriting.
1 parent 7a772af commit 75178f9

File tree

3 files changed

+329
-30
lines changed

3 files changed

+329
-30
lines changed

include/mockturtle/algorithms/window_rewriting.hpp

Lines changed: 168 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ struct window_rewriting_params
5151
uint64_t cut_size{6};
5252
uint64_t num_levels{5};
5353

54+
/* Level information guides the windowing construction and as such impacts QoR:
55+
-- dont_update: fastest, but levels are wrong (QoR degrades)
56+
-- eager: fast, some levels are wrong
57+
-- precise: fast, all levels are correct (best QoR)
58+
-- recompute: slow, same as precise (used only for debugging)
59+
*/
60+
enum
61+
{
62+
/* do not update any levels */
63+
dont_update,
64+
/* eagerly update the levels of changed nodes but avoid
65+
topological sorting (some levels will be wrong) */
66+
eager,
67+
/* precisely update the levels of changed nodes bottom-to-top and
68+
in topological order */
69+
precise,
70+
/* recompute all levels (also precise, but more expensive to
71+
compute) */
72+
recompute,
73+
} level_update_strategy = dont_update;
74+
5475
bool filter_cyclic_substitutions{false};
5576
}; /* window_rewriting_params */
5677

@@ -77,6 +98,9 @@ struct window_rewriting_stats
7798
/*! \brief Time for encoding index_list. */
7899
stopwatch<>::duration time_encode{0};
79100

101+
/*! \brief Time for detecting cycles. */
102+
stopwatch<>::duration time_cycle{0};
103+
80104
/*! \brief Total number of calls to the resub. engine. */
81105
uint64_t num_substitutions{0};
82106
uint64_t num_restrashes{0};
@@ -93,6 +117,7 @@ struct window_rewriting_stats
93117
time_topo_sort += other.time_topo_sort;
94118
time_encode += other.time_encode;
95119
num_substitutions += other.num_substitutions;
120+
num_restrashes += other.num_restrashes;
96121
num_windows += other.num_windows;
97122
gain += other.gain;
98123
return *this;
@@ -177,20 +202,24 @@ class window_rewriting_impl
177202
: ntk( ntk )
178203
, ps( ps )
179204
, st( st )
205+
/* initialize levels to network depth */
206+
, levels( ntk.depth() )
180207
{
181208
auto const update_level_of_new_node = [&]( const auto& n ) {
182-
ntk.resize_levels();
183-
update_node_level( n );
209+
stopwatch t( st.time_total );
210+
update_levels( n );
184211
};
185212

186213
auto const update_level_of_existing_node = [&]( node const& n, const auto& old_children ) {
187214
(void)old_children;
188-
ntk.resize_levels();
189-
update_node_level( n );
215+
stopwatch t( st.time_total );
216+
update_levels( n );
190217
};
191218

192219
auto const update_level_of_deleted_node = [&]( node const& n ) {
220+
stopwatch t( st.time_total );
193221
assert( ntk.fanout_size( n ) == 0u );
222+
assert( ntk.is_dead( n ) );
194223
ntk.set_level( n, -1 );
195224
};
196225

@@ -205,7 +234,7 @@ class window_rewriting_impl
205234

206235
create_window_impl windowing( ntk );
207236
uint32_t const size = ntk.size();
208-
for ( uint32_t n = 0u; n < std::min( size, ntk.size() ); ++n )
237+
for ( uint32_t n = 0u; n < size; ++n )
209238
{
210239
if ( ntk.is_constant( n ) || ntk.is_ci( n ) || ntk.is_dead( n ) )
211240
{
@@ -247,6 +276,9 @@ class window_rewriting_impl
247276
uint32_t counter{0};
248277
++st.num_substitutions;
249278

279+
/* ensure that no dead nodes are reachable */
280+
assert( count_reachable_dead_nodes( ntk ) == 0u );
281+
250282
std::list<std::pair<node, signal>> substitutions;
251283
insert( ntk, std::begin( signals ), std::end( signals ), *il_opt,
252284
[&]( signal const& _new )
@@ -260,34 +292,52 @@ class window_rewriting_impl
260292

261293
/* ensure that _old is not in the TFI of _new */
262294
// assert( !is_contained_in_tfi( ntk, ntk.get_node( _new ), ntk.get_node( _old ) ) );
263-
if ( ps.filter_cyclic_substitutions && is_contained_in_tfi( ntk, ntk.get_node( _new ), ntk.get_node( _old ) ) )
295+
if ( ps.filter_cyclic_substitutions &&
296+
call_with_stopwatch( st.time_window, [&](){ return is_contained_in_tfi( ntk, ntk.get_node( _new ), ntk.get_node( _old ) ); }) )
264297
{
265298
std::cout << "undo resubstitution " << ntk.get_node( _old ) << std::endl;
266-
if ( ntk.fanout_size( ntk.get_node( _new ) ) == 0u )
299+
substitutions.emplace_back( std::make_pair( ntk.get_node( _old ), ntk.is_complemented( _old ) ? !_new : _new ) );
300+
for ( auto it = std::rbegin( substitutions ); it != std::rend( substitutions ); ++it )
267301
{
268-
ntk.take_out_node( ntk.get_node( _new ) );
302+
if ( ntk.fanout_size( ntk.get_node( it->second ) ) == 0u )
303+
{
304+
ntk.take_out_node( ntk.get_node( it->second ) );
305+
}
269306
}
307+
substitutions.clear();
270308
return false;
271309
}
272310

273311
substitutions.emplace_back( std::make_pair( ntk.get_node( _old ), ntk.is_complemented( _old ) ? !_new : _new ) );
274312
return true;
275313
});
276314

315+
/* ensure that no dead nodes are reachable */
316+
assert( count_reachable_dead_nodes( ntk ) == 0u );
277317
substitute_nodes( substitutions );
278318

279319
/* recompute levels and depth */
280-
// call_with_stopwatch( st.time_levels, [&]() { ntk.update_levels(); } );
281-
update_depth();
320+
if ( ps.level_update_strategy == window_rewriting_params::recompute )
321+
{
322+
call_with_stopwatch( st.time_levels, [&]() { ntk.update_levels(); } );
323+
}
324+
if ( ps.level_update_strategy != window_rewriting_params::dont_update )
325+
{
326+
update_depth();
327+
}
282328

283329
/* ensure that no dead nodes are reachable */
284330
assert( count_reachable_dead_nodes( ntk ) == 0u );
285331

286332
/* ensure that the network structure is still acyclic */
287333
assert( network_is_acylic( ntk ) );
288334

289-
/* ensure that the levels and depth is correct */
290-
assert( check_network_levels( ntk ) );
335+
if ( ps.level_update_strategy == window_rewriting_params::precise ||
336+
ps.level_update_strategy == window_rewriting_params::recompute )
337+
{
338+
/* ensure that the levels and depth is correct */
339+
assert( check_network_levels( ntk ) );
340+
}
291341

292342
/* update internal data structures in windowing */
293343
windowing.resize( ntk.size() );
@@ -370,7 +420,7 @@ class window_rewriting_impl
370420
{
371421
ntk.decr_fanout_size( nn );
372422
}
373-
/* remove the node if it's fanout_size becomes 0 */
423+
/* remove the node if its fanout_size becomes 0 */
374424
if ( ntk.fanout_size( nn ) == 0 )
375425
{
376426
ntk.take_out_node( nn );
@@ -399,24 +449,27 @@ class window_rewriting_impl
399449
auto const [old_node, new_signal] = substitutions.front();
400450
substitutions.pop_front();
401451

402-
// for ( auto index = 1u; index < _storage->nodes.size(); ++index )
403-
const auto parents = ntk.fanout( old_node );
404-
for ( auto index : parents )
452+
for ( auto index : ntk.fanout( old_node ) )
405453
{
406454
/* skip CIs and dead nodes */
407455
if ( ntk.is_dead( index ) )
456+
{
408457
continue;
458+
}
409459

410460
/* skip nodes that will be deleted */
411461
if ( std::find_if( std::begin( substitutions ), std::end( substitutions ),
412462
[&index]( auto s ){ return s.first == index; } ) != std::end( substitutions ) )
463+
{
413464
continue;
465+
}
414466

415467
/* replace in node */
416468
if ( const auto repl = ntk.replace_in_node( index, old_node, new_signal ); repl )
417469
{
418470
ntk.incr_fanout_size( ntk.get_node( repl->second ) );
419471
substitutions.emplace_back( *repl );
472+
++st.num_restrashes;
420473
}
421474
}
422475

@@ -442,16 +495,102 @@ class window_rewriting_impl
442495

443496
/* decrement fanout_size when released from substitution list */
444497
ntk.decr_fanout_size( ntk.get_node( new_signal ) );
498+
if ( ntk.fanout_size( ntk.get_node( new_signal ) ) == 0 )
499+
{
500+
ntk.take_out_node( ntk.get_node( new_signal ) );
501+
}
445502
}
446503

447504
ntk._events->on_delete.pop_back();
448505
}
449506

450-
/* recursively update the node levels and the depth of the critical path */
451-
void update_node_level( node const& n )
507+
void update_levels( node const& n )
452508
{
453-
uint32_t const curr_level = ntk.level( n );
509+
ntk.resize_levels();
510+
if ( ps.level_update_strategy == window_rewriting_params::precise )
511+
{
512+
call_with_stopwatch( st.time_levels, [&]() { update_node_level_precise( n ); } );
513+
}
514+
else if ( ps.level_update_strategy == window_rewriting_params::eager )
515+
{
516+
call_with_stopwatch( st.time_levels, [&]() { update_node_level_eager( n ); } );
517+
}
518+
519+
/* levels can be wrong until substitute_nodes has finished */
520+
// assert( check_network_levels( ntk ) );
521+
}
522+
523+
/* precisely update node levels using an iterative topological sorting approach */
524+
void update_node_level_precise( node const& n )
525+
{
526+
assert( count_reachable_dead_nodes_from_node( ntk, n ) == 0u );
527+
// assert( count_nodes_with_dead_fanins( ntk, n ) == 0u );
528+
529+
/* compute level of current node */
530+
uint32_t level_offset{0};
531+
ntk.foreach_fanin( n, [&]( signal const& fi ){
532+
level_offset = std::max( ntk.level( ntk.get_node( fi ) ), level_offset );
533+
});
534+
++level_offset;
535+
536+
/* add node into levels */
537+
if ( levels.size() < 1u )
538+
{
539+
levels.resize( 1u );
540+
}
541+
levels[0].emplace_back( n );
542+
543+
for ( uint32_t level_index = 0u; level_index < levels.size(); ++level_index )
544+
{
545+
if ( levels[level_index].empty() )
546+
continue;
547+
548+
for ( uint32_t node_index = 0u; node_index < levels[level_index].size(); ++node_index )
549+
{
550+
node const p = levels[level_index][node_index];
551+
552+
/* recompute level of this node */
553+
uint32_t lvl{0};
554+
ntk.foreach_fanin( p, [&]( signal const& fi ){
555+
if ( ntk.is_dead( ntk.get_node( fi ) ) )
556+
return;
557+
558+
lvl = std::max( ntk.level( ntk.get_node( fi ) ), lvl );
559+
return;
560+
});
561+
++lvl;
562+
assert( lvl > 0 );
454563

564+
/* update level and add fanouts to levels[.] if the recomputed
565+
level is different from the current level */
566+
if ( lvl != ntk.level( p ) )
567+
{
568+
ntk.set_level( p, lvl );
569+
ntk.foreach_fanout( p, [&]( node const& fo ){
570+
assert( std::max( ntk.level( fo ), lvl + 1 ) >= level_offset );
571+
uint32_t const pos = std::max( ntk.level( fo ), lvl + 1 ) - level_offset;
572+
assert( pos >= 0u );
573+
assert( pos >= level_index );
574+
if ( levels.size() <= pos )
575+
{
576+
levels.resize( std::max( uint32_t( levels.size() << 1 ), pos + 1 ) );
577+
}
578+
levels[pos].emplace_back( fo );
579+
});
580+
}
581+
}
582+
583+
/* clean the level */
584+
levels[level_index].clear();
585+
}
586+
levels.clear();
587+
}
588+
589+
/* eagerly update the node levels without topologically sorting (may
590+
stack-overflow if the network is deep)*/
591+
void update_node_level_eager( node const& n )
592+
{
593+
uint32_t const curr_level = ntk.level( n );
455594
uint32_t max_level = 0;
456595
ntk.foreach_fanin( n, [&]( const auto& f ) {
457596
auto const p = ntk.get_node( f );
@@ -469,21 +608,21 @@ class window_rewriting_impl
469608
ntk.foreach_fanout( n, [&]( const auto& p ) {
470609
if ( !ntk.is_dead( p ) )
471610
{
472-
update_node_level( p );
611+
update_node_level_eager( p );
473612
}
474613
} );
475614
}
476615
}
477616

617+
/* update network depth (needs level information!) */
478618
void update_depth()
479619
{
620+
stopwatch t( st.time_levels );
621+
480622
uint32_t max_level{0};
481-
ntk.foreach_co( [&]( signal s ){
623+
ntk.foreach_co( [&]( signal const& s ){
482624
assert( !ntk.is_dead( ntk.get_node( s ) ) );
483-
if ( ntk.level( ntk.get_node( s ) ) > max_level )
484-
{
485-
max_level = ntk.level( ntk.get_node( s ) );
486-
}
625+
max_level = std::max( ntk.level( ntk.get_node( s ) ), max_level );
487626
});
488627

489628
if ( ntk.depth() != max_level )
@@ -496,9 +635,11 @@ class window_rewriting_impl
496635
Ntk& ntk;
497636
window_rewriting_params ps;
498637
window_rewriting_stats& st;
499-
}; /* window_rewriting_impl */
500638

501-
} /* detail */
639+
std::vector<std::vector<node>> levels;
640+
};
641+
642+
} /* namespace detail */
502643

503644
template<class Ntk>
504645
void window_rewriting( Ntk& ntk, window_rewriting_params const& ps = {}, window_rewriting_stats* pst = nullptr )

0 commit comments

Comments
 (0)