From 75abcd376beb39ee163b5db9ec9d87802a4ead33 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Wed, 28 Feb 2024 09:51:32 +0100 Subject: [PATCH] Adding bindings to use ACD66 instead of generic ACD --- src/map/if/acd/ac_wrapper.cpp | 96 +++++++++++++------ src/map/if/acd/acd66.hpp | 169 ++++++++++++++++++++++++++++++++-- 2 files changed, 229 insertions(+), 36 deletions(-) diff --git a/src/map/if/acd/ac_wrapper.cpp b/src/map/if/acd/ac_wrapper.cpp index be1e8783a..7786f0e72 100644 --- a/src/map/if/acd/ac_wrapper.cpp +++ b/src/map/if/acd/ac_wrapper.cpp @@ -23,52 +23,92 @@ ABC_NAMESPACE_IMPL_START +static constexpr bool use_generic_acd = true; + int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ) { using namespace acd; - ac_decomposition_params ps; - ps.lut_size = lutSize; - ps.try_no_late_arrival = static_cast( try_no_late_arrival ); /* TODO: additional tests */ - ac_decomposition_stats st; - - ac_decomposition_impl acd( nVars, ps, &st ); - int val = acd.run( pTruth, *pdelay ); - - if ( val < 0 ) + if ( use_generic_acd ) { - *pdelay = 0; - return -1; + ac_decomposition_params ps; + ps.lut_size = lutSize; + ps.try_no_late_arrival = static_cast( try_no_late_arrival ); /* TODO: additional tests */ + ac_decomposition_stats st; + + ac_decomposition_impl acd( nVars, ps, &st ); + int val = acd.run( pTruth, *pdelay ); + + if ( val < 0 ) + { + *pdelay = 0; + return -1; + } + + *pdelay = acd.get_profile(); + *cost = 2; + + return val; } + else + { + acd66_impl acd( nVars ); + int val = acd.run( pTruth, *pdelay ); - *pdelay = acd.get_profile(); - *cost = st.num_luts; + if ( val == 0 ) + { + *pdelay = 0; + return -1; + } - return val; + *pdelay = acd.get_profile(); + *cost = 2; + + return val; + } } int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ) { using namespace acd; - ac_decomposition_params ps; - ps.lut_size = lutSize; - ac_decomposition_stats st; - - ac_decomposition_impl acd( nVars, ps, &st ); - acd.run( pTruth, *pdelay ); - int val = acd.compute_decomposition(); - - if ( val < 0 ) + if ( use_generic_acd ) { - *pdelay = 0; - return -1; + ac_decomposition_params ps; + ps.lut_size = lutSize; + ac_decomposition_stats st; + + ac_decomposition_impl acd( nVars, ps, &st ); + acd.run( pTruth, *pdelay ); + int val = acd.compute_decomposition(); + + if ( val < 0 ) + { + *pdelay = 0; + return -1; + } + + *pdelay = acd.get_profile(); + acd.get_decomposition( decomposition ); + return 0; } + else + { + acd66_impl acd( nVars ); + acd.run( pTruth, *pdelay ); + int val = acd.compute_decomposition(); - *pdelay = acd.get_profile(); + if ( val != 0 ) + { + *pdelay = 0; + return -1; + } - acd.get_decomposition( decomposition ); - return 0; + *pdelay = acd.get_profile(); + + acd.get_decomposition( decomposition ); + return 0; + } } int acd66_evaluate( word * pTruth, unsigned nVars, int compute_decomposition ) diff --git a/src/map/if/acd/acd66.hpp b/src/map/if/acd/acd66.hpp index 52de4581b..92caf3b57 100644 --- a/src/map/if/acd/acd66.hpp +++ b/src/map/if/acd/acd66.hpp @@ -76,6 +76,34 @@ public: return find_decomposition() ? 1 : 0; } + /*! \brief Runs ACD 66 */ + int run( word* ptt, unsigned delay_profile ) + { + assert( num_vars > 6 ); + + /* truth table is too large for the settings */ + if ( num_vars > max_num_vars || num_vars > 11 ) + { + return false; + } + + uint32_t late_arriving = __builtin_popcount( delay_profile ); + + /* too many late arriving variables */ + if ( late_arriving > 5 ) + return 0; + + /* convert to static TT */ + init_truth_table( ptt ); + best_tt = start_tt; + + /* permute late arriving variables to be the least significant */ + reposition_late_arriving_variables( delay_profile, late_arriving ); + + /* run ACD trying different bound sets and free sets */ + return find_decomposition_offset( late_arriving ) ? ( delay_profile == 0 ? 2 : 1 ) : 0; + } + int compute_decomposition() { if ( best_multiplicity == UINT32_MAX ) @@ -102,17 +130,17 @@ public: return bs_support_size + best_free_set + 1 + ( best_multiplicity > 2 ? 1 : 0 ); } - /* contains a 1 for BS variables */ + /* contains a 1 for FS variables */ unsigned get_profile() { unsigned profile = 0; - if ( bs_support_size == UINT32_MAX ) + if ( best_multiplicity == UINT32_MAX ) return -1; - for ( uint32_t i = 0; i < bs_support_size; ++i ) + for ( uint32_t i = 0; i < best_free_set; ++i ) { - profile |= 1 << permutations[best_free_set + bs_support[i]]; + profile |= 1 << permutations[i]; } return profile; @@ -143,6 +171,22 @@ private: return false; } + bool find_decomposition_offset( uint32_t offset ) + { + best_multiplicity = UINT32_MAX; + best_free_set = UINT32_MAX; + + /* find ACD "66" for different number of variables in the free set */ + for ( uint32_t i = std::max( num_vars - 6, offset ); i <= 5; ++i ) + { + if ( find_decomposition_bs_offset( i, offset ) ) + return true; + } + + best_multiplicity = UINT32_MAX; + return false; + } + void init_truth_table( word* ptt ) { uint32_t const num_blocks = ( num_vars <= 6 ) ? 1 : ( 1 << ( num_vars - 6 ) ); @@ -190,13 +234,13 @@ private: return size; } - inline bool combinations_next( uint32_t k, uint32_t* pComb, uint32_t* pInvPerm, STT& tt ) + inline bool combinations_next( uint32_t k, uint32_t offset, uint32_t* pComb, uint32_t* pInvPerm, STT& tt ) { uint32_t i; for ( i = k - 1; pComb[i] == num_vars - k + i; --i ) { - if ( i == 0 ) + if ( i == offset ) return false; } @@ -254,7 +298,7 @@ private: best_multiplicity = cost; int res = check_shared_set( tt ); - if ( res > 0 ) + if ( res >= 0 ) { best_tt = tt; for ( uint32_t i = 0; i < num_vars; ++i ) @@ -267,7 +311,96 @@ private: return true; } } - } while ( combinations_next( free_set_size, pComb, pInvPerm, tt ) ); + } while ( combinations_next( free_set_size, 0, pComb, pInvPerm, tt ) ); + + return false; + } + + bool find_decomposition_bs_offset( uint32_t free_set_size, uint32_t offset ) + { + STT tt = best_tt; + + /* works up to 16 input truth tables */ + assert( num_vars <= 16 ); + best_free_set = free_set_size; + + /* special case */ + if ( free_set_size == offset ) + { + uint32_t cost = column_multiplicity( tt, free_set_size ); + if ( cost == 2 ) + { + best_tt = tt; + best_multiplicity = cost; + return true; + } + else if ( cost <= 4 && free_set_size < 5 ) + { + /* look for a shared variable */ + best_multiplicity = cost; + int res = check_shared_set( tt ); + + if ( res >= 0 ) + { + best_tt = tt; + /* move shared variable as the most significative one */ + swap_inplace_local( best_tt, res, num_vars - 1 ); + std::swap( permutations[res], permutations[num_vars - 1] ); + return true; + } + } + return false; + } + + /* init combinations */ + uint32_t pComb[16], pInvPerm[16]; + for ( uint32_t i = 0; i < num_vars; ++i ) + { + pComb[i] = pInvPerm[i] = i; + } + + /* enumerate combinations */ + do + { + uint32_t cost = column_multiplicity( tt, free_set_size ); + if ( cost == 2 ) + { + best_tt = tt; + best_multiplicity = cost; + for ( uint32_t i = 0; i < num_vars; ++i ) + { + pInvPerm[i] = permutations[pComb[i]]; + } + for ( uint32_t i = 0; i < num_vars; ++i ) + { + permutations[i] = pInvPerm[i]; + } + return true; + } + else if ( cost <= 4 && free_set_size < 5 ) + { + /* look for a shared variable */ + best_multiplicity = cost; + int res = check_shared_set( tt ); + + if ( res >= 0 ) + { + best_tt = tt; + for ( uint32_t i = 0; i < num_vars; ++i ) + { + pInvPerm[i] = permutations[pComb[i]]; + } + for ( uint32_t i = 0; i < num_vars; ++i ) + { + permutations[i] = pInvPerm[i]; + } + /* move shared variable as the most significative one */ + swap_inplace_local( best_tt, res, num_vars - 1 ); + std::swap( permutations[res], permutations[num_vars - 1] ); + return true; + } + } + } while ( combinations_next( free_set_size, offset, pComb, pInvPerm, tt ) ); return false; } @@ -552,6 +685,26 @@ private: } } + inline void reposition_late_arriving_variables( unsigned delay_profile, uint32_t late_arriving ) + { + uint32_t k = 0; + for ( uint32_t i = 0; i < late_arriving; ++i ) + { + while ( ( ( delay_profile >> k ) & 1 ) == 0 ) + ++k; + + if ( permutations[i] == k ) + { + ++k; + continue; + } + + std::swap( permutations[i], permutations[k] ); + swap_inplace_local( best_tt, i, k ); + ++k; + } + } + template void local_extend_to( TT_type& tt, uint32_t real_num_vars ) {