summaryrefslogtreecommitdiffstats
path: root/src/aig/gia/giaStr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/aig/gia/giaStr.c')
-rw-r--r--src/aig/gia/giaStr.c1812
1 files changed, 1809 insertions, 3 deletions
diff --git a/src/aig/gia/giaStr.c b/src/aig/gia/giaStr.c
index 13ddb233..f3416683 100644
--- a/src/aig/gia/giaStr.c
+++ b/src/aig/gia/giaStr.c
@@ -6,7 +6,7 @@
PackageName [Scalable AIG package.]
- Synopsis [Cut computation.]
+ Synopsis [AIG structuring.]
Author [Alan Mishchenko]
@@ -19,6 +19,9 @@
***********************************************************************/
#include "gia.h"
+#include "misc/util/utilNam.h"
+#include "misc/vec/vecWec.h"
+#include "misc/tim/tim.h"
ABC_NAMESPACE_IMPL_START
@@ -26,15 +29,1343 @@ ABC_NAMESPACE_IMPL_START
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
+#define STR_SUPER 100
+
+enum {
+ STR_NONE = 0,
+ STR_CONST0 = 1,
+ STR_PI = 2,
+ STR_AND = 3,
+ STR_XOR = 4,
+ STR_MUX = 5,
+ STR_BUF = 6,
+ STR_PO = 7,
+ STR_UNUSED = 8
+};
+
+typedef struct Str_Obj_t_ Str_Obj_t;
+struct Str_Obj_t_
+{
+ unsigned Type : 4; // object type
+ unsigned nFanins : 28; // fanin count
+ int iOffset; // place where fanins are stored
+ int iTop; // top level MUX
+ int iCopy; // copy of this node
+};
+typedef struct Str_Ntk_t_ Str_Ntk_t;
+struct Str_Ntk_t_
+{
+ int nObjs; // object count
+ int nObjsAlloc; // alloc objects
+ Str_Obj_t * pObjs; // objects
+ Vec_Int_t vFanins; // object fanins
+ int nObjCount[STR_UNUSED];
+ int nTrees;
+ int nGroups;
+ int DelayGain;
+};
+typedef struct Str_Man_t_ Str_Man_t;
+struct Str_Man_t_
+{
+ // user data
+ Gia_Man_t * pOld; // manager
+ int nLutSize; // LUT size
+ int fCutMin; // cut minimization
+ // internal data
+ Str_Ntk_t * pNtk; // balanced network
+ // AIG under construction
+ Gia_Man_t * pNew; // newly constructed
+ Vec_Int_t * vDelays; // delays of each object
+};
+
+static inline Str_Obj_t * Str_NtkObj( Str_Ntk_t * p, int i ) { assert( i < p->nObjs ); return p->pObjs + i; }
+static inline int Str_ObjFaninId( Str_Ntk_t * p, Str_Obj_t * pObj, int i ) { return Abc_Lit2Var( Vec_IntEntry(&p->vFanins, pObj->iOffset + i) ); }
+static inline Str_Obj_t * Str_ObjFanin( Str_Ntk_t * p, Str_Obj_t * pObj, int i ) { return Str_NtkObj( p, Str_ObjFaninId(p, pObj, i) ); }
+static inline int Str_ObjFaninC( Str_Ntk_t * p, Str_Obj_t * pObj, int i ) { return Abc_LitIsCompl( Vec_IntEntry(&p->vFanins, pObj->iOffset + i) ); }
+static inline int Str_ObjFaninCopy( Str_Ntk_t * p, Str_Obj_t * pObj, int i ) { return Abc_LitNotCond( Str_ObjFanin(p, pObj, i)->iCopy, Str_ObjFaninC(p, pObj, i) ); }
+static inline int Str_ObjId( Str_Ntk_t * p, Str_Obj_t * pObj ) { return pObj - p->pObjs; }
+
+#define Str_NtkManForEachObj( p, pObj ) \
+ for ( pObj = p->pObjs; Str_ObjId(p, pObj) < p->nObjs; pObj++ )
+#define Str_NtkManForEachObjVec( vVec, p, pObj, i ) \
+ for ( i = 0; (i < Vec_IntSize(vVec)) && ((pObj) = Str_NtkObj(p, Vec_IntEntry(vVec,i))); i++ )
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
+/**Function*************************************************************
+
+ Synopsis [Logic network manipulation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Str_ObjCreate( Str_Ntk_t * p, int Type, int nFanins, int * pFanins )
+{
+ Str_Obj_t * pObj = p->pObjs + p->nObjs; int i;
+ assert( p->nObjs < p->nObjsAlloc );
+ pObj->Type = Type;
+ pObj->nFanins = nFanins;
+ pObj->iOffset = Vec_IntSize(&p->vFanins);
+ pObj->iTop = pObj->iCopy = -1;
+ for ( i = 0; i < nFanins; i++ )
+ {
+ Vec_IntPush( &p->vFanins, pFanins[i] );
+ assert( pFanins[i] >= 0 );
+ }
+ p->nObjCount[Type]++;
+ return Abc_Var2Lit( p->nObjs++, 0 );
+}
+static inline Str_Ntk_t * Str_NtkCreate( int nObjsAlloc, int nFaninsAlloc )
+{
+ Str_Ntk_t * p;
+ p = ABC_CALLOC( Str_Ntk_t, 1 );
+ p->pObjs = ABC_ALLOC( Str_Obj_t, nObjsAlloc );
+ p->nObjsAlloc = nObjsAlloc;
+ Str_ObjCreate( p, STR_CONST0, 0, NULL );
+ Vec_IntGrow( &p->vFanins, nFaninsAlloc );
+ return p;
+}
+static inline void Str_NtkDelete( Str_Ntk_t * p )
+{
+// printf( "Total delay gain = %d.\n", p->DelayGain );
+ ABC_FREE( p->vFanins.pArray );
+ ABC_FREE( p->pObjs );
+ ABC_FREE( p );
+}
+static inline void Str_NtkPs( Str_Ntk_t * p, abctime clk )
+{
+ printf( "Network contains %d ands, %d xors, %d muxes (%d trees in %d groups). ",
+ p->nObjCount[STR_AND], p->nObjCount[STR_XOR], p->nObjCount[STR_MUX], p->nTrees, p->nGroups );
+ Abc_PrintTime( 1, "Time", clk );
+}
+static inline void Str_ObjReadGroup( Str_Ntk_t * p, Str_Obj_t * pObj, int * pnGroups, int * pnMuxes )
+{
+ Str_Obj_t * pObj1, * pObj2;
+ *pnGroups = *pnMuxes = 0;
+ if ( pObj->iTop == 0 )
+ return;
+ pObj1 = Str_NtkObj( p, pObj->iTop );
+ pObj2 = Str_NtkObj( p, pObj1->iTop );
+ *pnMuxes = pObj1 - pObj + 1;
+ *pnGroups = (pObj2 - pObj + 1) / *pnMuxes;
+}
+static inline void Str_NtkPrintGroups( Str_Ntk_t * p )
+{
+ Str_Obj_t * pObj;
+ int nGroups, nMuxes;
+ Str_NtkManForEachObj( p, pObj )
+ if ( pObj->Type == STR_MUX && pObj->iTop > 0 )
+ {
+ Str_ObjReadGroup( p, pObj, &nGroups, &nMuxes );
+ pObj += nGroups * nMuxes - 1;
+ printf( "%d x %d ", nGroups, nMuxes );
+ }
+ printf( "\n" );
+}
+Gia_Man_t * Str_NtkToGia( Gia_Man_t * pGia, Str_Ntk_t * p )
+{
+ Gia_Man_t * pNew, * pTemp;
+ Str_Obj_t * pObj; int k;
+ assert( pGia->pMuxes == NULL );
+ pNew = Gia_ManStart( 3 * Gia_ManObjNum(pGia) / 2 );
+ pNew->pName = Abc_UtilStrsav( pGia->pName );
+ pNew->pSpec = Abc_UtilStrsav( pGia->pSpec );
+ Gia_ManHashStart( pNew );
+ Str_NtkManForEachObj( p, pObj )
+ {
+ if ( pObj->Type == STR_PI )
+ pObj->iCopy = Gia_ManAppendCi( pNew );
+ else if ( pObj->Type == STR_AND )
+ {
+ pObj->iCopy = 1;
+ for ( k = 0; k < (int)pObj->nFanins; k++ )
+ pObj->iCopy = Gia_ManHashAnd( pNew, pObj->iCopy, Str_ObjFaninCopy(p, pObj, k) );
+ }
+ else if ( pObj->Type == STR_XOR )
+ {
+ pObj->iCopy = 0;
+ for ( k = 0; k < (int)pObj->nFanins; k++ )
+ pObj->iCopy = Gia_ManHashXor( pNew, pObj->iCopy, Str_ObjFaninCopy(p, pObj, k) );
+ }
+ else if ( pObj->Type == STR_MUX )
+ pObj->iCopy = Gia_ManHashMux( pNew, Str_ObjFaninCopy(p, pObj, 2), Str_ObjFaninCopy(p, pObj, 1), Str_ObjFaninCopy(p, pObj, 0) );
+ else if ( pObj->Type == STR_PO )
+ pObj->iCopy = Gia_ManAppendCo( pNew, Str_ObjFaninCopy(p, pObj, 0) );
+ else if ( pObj->Type == STR_CONST0 )
+ pObj->iCopy = 0;
+ else assert( 0 );
+ }
+ Gia_ManHashStop( pNew );
+// assert( Gia_ManObjNum(pNew) <= Gia_ManObjNum(pGia) );
+ Gia_ManSetRegNum( pNew, Gia_ManRegNum(pGia) );
+ pNew = Gia_ManCleanup( pTemp = pNew );
+ Gia_ManStop( pTemp );
+ return pNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Constructs a normalized AIG without structural hashing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Gia_Man_t * Gia_ManDupMuxesNoHash( Gia_Man_t * p )
+{
+ Gia_Man_t * pNew;
+ Gia_Obj_t * pObj, * pFan0, * pFan1, * pFanC;
+ int i, iLit0, iLit1, fCompl;
+ assert( p->pMuxes == NULL );
+ ABC_FREE( p->pRefs );
+ Gia_ManCreateRefs( p );
+ // discount nodes with one fanout pointed to by MUX type
+ Gia_ManForEachAnd( p, pObj, i )
+ {
+ if ( !Gia_ObjIsMuxType(pObj) )
+ continue;
+ Gia_ObjRefDec(p, Gia_ObjFanin0(pObj));
+ Gia_ObjRefDec(p, Gia_ObjFanin1(pObj));
+ }
+ // start the new manager
+ pNew = Gia_ManStart( Gia_ManObjNum(p) );
+ pNew->pName = Abc_UtilStrsav( p->pName );
+ pNew->pSpec = Abc_UtilStrsav( p->pSpec );
+ pNew->pMuxes = ABC_CALLOC( unsigned, pNew->nObjsAlloc );
+ Gia_ManFillValue(p);
+ Gia_ManConst0(p)->Value = 0;
+ Gia_ManForEachCi( p, pObj, i )
+ pObj->Value = Gia_ManAppendCi( pNew );
+ Gia_ManForEachAnd( p, pObj, i )
+ {
+ if ( !Gia_ObjRefNumId(p, i) )
+ continue;
+ if ( !Gia_ObjIsMuxType(pObj) )
+ pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
+ else if ( Gia_ObjRecognizeExor(pObj, &pFan0, &pFan1) )
+ {
+ iLit0 = Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFan0));
+ iLit1 = Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFan1));
+ fCompl = Abc_LitIsCompl(iLit0) ^ Abc_LitIsCompl(iLit1);
+ pObj->Value = fCompl ^ Gia_ManAppendXorReal( pNew, Abc_LitRegular(iLit0), Abc_LitRegular(iLit1) );
+ }
+ else
+ {
+ pFanC = Gia_ObjRecognizeMux( pObj, &pFan1, &pFan0 );
+ iLit0 = Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFan0));
+ iLit1 = Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFan1));
+ if ( iLit0 == iLit1 )
+ pObj->Value = iLit0;
+ else if ( Abc_Lit2Var(iLit0) == Abc_Lit2Var(iLit1) )
+ {
+ iLit1 = Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFanC));
+ fCompl = Abc_LitIsCompl(iLit0) ^ Abc_LitIsCompl(iLit1);
+ pObj->Value = fCompl ^ Gia_ManAppendXorReal( pNew, Abc_LitRegular(iLit0), Abc_LitRegular(iLit1) );
+ }
+ else
+ pObj->Value = Gia_ManAppendMuxReal( pNew, Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFanC)), Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFan1)), Gia_ObjLitCopy(p, Gia_ObjToLit(p, pFan0)) );
+ }
+ }
+ Gia_ManForEachCo( p, pObj, i )
+ pObj->Value = Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) );
+ Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) );
+ assert( !Gia_ManHasDangling(pNew) );
+ return pNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Constructs AIG ordered for balancing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Str_MuxInputsCollect_rec( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vNodes )
+{
+ if ( !pObj->fMark0 )
+ {
+ Vec_IntPush( vNodes, Gia_ObjId(p, pObj) );
+ return;
+ }
+ Vec_IntPush( vNodes, Gia_ObjFaninId2p(p, pObj) );
+ Str_MuxInputsCollect_rec( p, Gia_ObjFanin0(pObj), vNodes );
+ Str_MuxInputsCollect_rec( p, Gia_ObjFanin1(pObj), vNodes );
+}
+void Str_MuxInputsCollect( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vNodes )
+{
+ assert( !pObj->fMark0 );
+ pObj->fMark0 = 1;
+ Vec_IntClear( vNodes );
+ Str_MuxInputsCollect_rec( p, pObj, vNodes );
+ pObj->fMark0 = 0;
+}
+void Str_MuxStructCollect_rec( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vNodes )
+{
+ if ( !pObj->fMark0 )
+ return;
+ Str_MuxStructCollect_rec( p, Gia_ObjFanin0(pObj), vNodes );
+ Str_MuxStructCollect_rec( p, Gia_ObjFanin1(pObj), vNodes );
+ Vec_IntPush( vNodes, Gia_ObjId(p, pObj) );
+}
+void Str_MuxStructCollect( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vNodes )
+{
+ assert( !pObj->fMark0 );
+ pObj->fMark0 = 1;
+ Vec_IntClear( vNodes );
+ Str_MuxStructCollect_rec( p, pObj, vNodes );
+ pObj->fMark0 = 0;
+}
+void Str_MuxStructDump_rec( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Str_t * vStr )
+{
+ if ( !pObj->fMark0 )
+ return;
+ Vec_StrPush( vStr, '[' );
+ Vec_StrPush( vStr, '(' );
+ Vec_StrPrintNum( vStr, Gia_ObjFaninId2p(p, pObj) );
+ Vec_StrPush( vStr, ')' );
+ Str_MuxStructDump_rec( p, Gia_ObjFaninC2(p, pObj) ? Gia_ObjFanin0(pObj) : Gia_ObjFanin1(pObj), vStr );
+ Vec_StrPush( vStr, '|' );
+ Str_MuxStructDump_rec( p, Gia_ObjFaninC2(p, pObj) ? Gia_ObjFanin1(pObj) : Gia_ObjFanin0(pObj), vStr );
+ Vec_StrPush( vStr, ']' );
+}
+void Str_MuxStructDump( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Str_t * vStr )
+{
+ assert( !pObj->fMark0 );
+ pObj->fMark0 = 1;
+ Vec_StrClear( vStr );
+ Str_MuxStructDump_rec( p, pObj, vStr );
+ Vec_StrPush( vStr, '\0' );
+ pObj->fMark0 = 0;
+}
+int Str_ManMuxCountOne( char * p )
+{
+ int Count = 0;
+ for ( ; *p; p++ )
+ Count += (*p == '[');
+ return Count;
+}
+Vec_Wec_t * Str_ManDeriveTrees( Gia_Man_t * p )
+{
+ int fPrintStructs = 0;
+ Abc_Nam_t * pNames;
+ Vec_Wec_t * vGroups;
+ Vec_Str_t * vStr;
+ Gia_Obj_t * pObj, * pFanin;
+ int i, iStructId, fFound;
+ assert( p->pMuxes != NULL );
+ // mark MUXes whose only fanout is a MUX
+ ABC_FREE( p->pRefs );
+ Gia_ManCreateRefs( p );
+ Gia_ManForEachMuxId( p, i )
+ {
+ pObj = Gia_ManObj(p, i);
+ pFanin = Gia_ObjFanin0(pObj);
+ if ( Gia_ObjIsMux(p, pFanin) && Gia_ObjRefNum(p, pFanin) == 1 )
+ pFanin->fMark0 = 1;
+ pFanin = Gia_ObjFanin1(pObj);
+ if ( Gia_ObjIsMux(p, pFanin) && Gia_ObjRefNum(p, pFanin) == 1 )
+ pFanin->fMark0 = 1;
+ }
+ // traverse for top level MUXes
+ vStr = Vec_StrAlloc( 1000 );
+ pNames = Abc_NamStart( 10000, 50 );
+ vGroups = Vec_WecAlloc( 1000 );
+ Vec_WecPushLevel( vGroups );
+ Gia_ManForEachMuxId( p, i )
+ {
+ // skip internal
+ pObj = Gia_ManObj(p, i);
+ if ( pObj->fMark0 )
+ continue;
+ // skip trees of size one
+ if ( !Gia_ObjFanin0(pObj)->fMark0 && !Gia_ObjFanin1(pObj)->fMark0 )
+ continue;
+ // hash the tree
+ Str_MuxStructDump( p, pObj, vStr );
+ iStructId = Abc_NamStrFindOrAdd( pNames, Vec_StrArray(vStr), &fFound );
+ if ( !fFound ) Vec_WecPushLevel( vGroups );
+ assert( Abc_NamObjNumMax(pNames) == Vec_WecSize(vGroups) );
+ Vec_IntPush( Vec_WecEntry(vGroups, iStructId), i );
+ }
+ if ( fPrintStructs )
+ {
+ char * pTemp;
+ Abc_NamManForEachObj( pNames, pTemp, i )
+ {
+ printf( "%5d : ", i );
+ printf( "Occur = %4d ", Vec_IntSize(Vec_WecEntry(vGroups,i)) );
+ printf( "Size = %4d ", Str_ManMuxCountOne(pTemp) );
+ printf( "%s\n", pTemp );
+ }
+ }
+ Abc_NamStop( pNames );
+ Vec_StrFree( vStr );
+ return vGroups;
+}
+Vec_Int_t * Str_ManCreateRoots( Vec_Wec_t * vGroups, int nObjs )
+{ // map tree MUXes into their classes
+ Vec_Int_t * vRoots;
+ Vec_Int_t * vGroup;
+ int i, k, Entry;
+ vRoots = Vec_IntStartFull( nObjs );
+ Vec_WecForEachLevel( vGroups, vGroup, i )
+ Vec_IntForEachEntry( vGroup, Entry, k )
+ Vec_IntWriteEntry( vRoots, Entry, i );
+ return vRoots;
+}
+
+void Str_MuxTraverse_rec( Gia_Man_t * p, int i )
+{
+ Gia_Obj_t * pObj;
+ if ( Gia_ObjIsTravIdCurrentId(p, i) )
+ return;
+ Gia_ObjSetTravIdCurrentId(p, i);
+ pObj = Gia_ManObj(p, i);
+ if ( !Gia_ObjIsAnd(pObj) )
+ return;
+ Str_MuxTraverse_rec(p, Gia_ObjFaninId0(pObj, i) );
+ Str_MuxTraverse_rec(p, Gia_ObjFaninId1(pObj, i) );
+ if ( Gia_ObjIsMux(p, pObj) )
+ Str_MuxTraverse_rec(p, Gia_ObjFaninId2(p, i) );
+}
+void Str_ManCheckOverlap( Gia_Man_t * p, Vec_Wec_t * vGroups )
+{ // check that members of each group are not in the TFI of each other
+ Vec_Int_t * vGroup, * vGroup2;
+ int i, k, n, iObj, iObj2;
+
+// vGroup = Vec_WecEntry(vGroups, 7);
+// Vec_IntForEachEntry( vGroup, iObj, n )
+// Gia_ManPrintCone2( p, Gia_ManObj(p, iObj) ), printf( "\n" );
+
+ Vec_WecForEachLevel( vGroups, vGroup, i )
+ Vec_IntForEachEntry( vGroup, iObj, k )
+ {
+ if ( Vec_IntSize(vGroup) == 1 )
+ continue;
+ // high light the cone
+ Gia_ManIncrementTravId( p );
+ Str_MuxTraverse_rec( p, iObj );
+ // check that none of the others are highlighted
+ Vec_IntForEachEntry( vGroup, iObj2, n )
+ if ( iObj != iObj2 && Gia_ObjIsTravIdCurrentId(p, iObj2) )
+ break;
+ if ( n == Vec_IntSize(vGroup) )
+ continue;
+ // split the group into individual trees
+ Vec_IntForEachEntryStart( vGroup, iObj2, n, 1 )
+ {
+ vGroup2 = Vec_WecPushLevel( vGroups );
+ vGroup = Vec_WecEntry( vGroups, i );
+ Vec_IntPush( vGroup2, iObj2 );
+ }
+ Vec_IntShrink( vGroup, 1 );
+
+/*
+ // this does not work because there can be a pair of independent trees
+ // with another tree squeezed in between them, so that there is a combo loop
+
+ // divide this group
+ nNew = 0;
+ vGroup2 = Vec_WecPushLevel( vGroups );
+ vGroup = Vec_WecEntry( vGroups, i );
+ Vec_IntForEachEntry( vGroup, iObj2, n )
+ {
+ if ( iObj != iObj2 && Gia_ObjIsTravIdCurrentId(p, iObj2) )
+ Vec_IntPush( vGroup2, iObj2 );
+ else
+ Vec_IntWriteEntry( vGroup, nNew++, iObj2 );
+ }
+ Vec_IntShrink( vGroup, nNew );
+ i--;
+ break;
+*/
+
+/*
+ // check that none of the others are highlighted
+ Vec_IntForEachEntry( vGroup, iObj, n )
+ if ( n != k && Gia_ObjIsTravIdCurrentId(p, iObj) )
+ {
+ printf( "Overlap of TFI cones of trees %d and %d in group %d of size %d!\n", k, n, i, Vec_IntSize(vGroup) );
+ Vec_IntShrink( vGroup, 1 );
+ break;
+ }
+*/
+ }
+}
/**Function*************************************************************
- Synopsis []
+ Synopsis [Simplify multi-input AND/XOR.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Gia_ManSimplifyXor( Vec_Int_t * vSuper )
+{
+ int i, k = 0, Prev = -1, This, fCompl = 0;
+ Vec_IntForEachEntry( vSuper, This, i )
+ {
+ if ( This == 0 )
+ continue;
+ if ( This == 1 )
+ fCompl ^= 1;
+ else if ( Prev != This )
+ Vec_IntWriteEntry( vSuper, k++, This ), Prev = This;
+ else
+ Prev = -1, k--;
+ }
+ Vec_IntShrink( vSuper, k );
+ if ( Vec_IntSize( vSuper ) == 0 )
+ Vec_IntPush( vSuper, fCompl );
+ else if ( fCompl )
+ Vec_IntWriteEntry( vSuper, 0, Abc_LitNot(Vec_IntEntry(vSuper, 0)) );
+}
+static inline void Gia_ManSimplifyAnd( Vec_Int_t * vSuper )
+{
+ int i, k = 0, Prev = -1, This;
+ Vec_IntForEachEntry( vSuper, This, i )
+ {
+ if ( This == 0 )
+ { Vec_IntFill(vSuper, 1, 0); return; }
+ if ( This == 1 )
+ continue;
+ if ( Prev == -1 || Abc_Lit2Var(Prev) != Abc_Lit2Var(This) )
+ Vec_IntWriteEntry( vSuper, k++, This ), Prev = This;
+ else if ( Prev != This )
+ { Vec_IntFill(vSuper, 1, 0); return; }
+ }
+ Vec_IntShrink( vSuper, k );
+ if ( Vec_IntSize( vSuper ) == 0 )
+ Vec_IntPush( vSuper, 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect multi-input AND/XOR.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Gia_ManSuperCollectXor_rec( Gia_Man_t * p, Gia_Obj_t * pObj )
+{
+ assert( !Gia_IsComplement(pObj) );
+ if ( !Gia_ObjIsXor(pObj) ||
+ Gia_ObjRefNum(p, pObj) > 1 ||
+// Gia_ObjRefNum(p, pObj) > 3 ||
+// (Gia_ObjRefNum(p, pObj) == 2 && (Gia_ObjRefNum(p, Gia_ObjFanin0(pObj)) == 1 || Gia_ObjRefNum(p, Gia_ObjFanin1(pObj)) == 1)) ||
+ Vec_IntSize(p->vSuper) > STR_SUPER )
+ {
+ Vec_IntPush( p->vSuper, Gia_ObjToLit(p, pObj) );
+ return;
+ }
+ assert( !Gia_ObjFaninC0(pObj) && !Gia_ObjFaninC1(pObj) );
+ Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin0(pObj) );
+ Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin1(pObj) );
+}
+static inline void Gia_ManSuperCollectAnd_rec( Gia_Man_t * p, Gia_Obj_t * pObj )
+{
+ if ( Gia_IsComplement(pObj) ||
+ !Gia_ObjIsAndReal(p, pObj) ||
+ Gia_ObjRefNum(p, pObj) > 1 ||
+// Gia_ObjRefNum(p, pObj) > 3 ||
+// (Gia_ObjRefNum(p, pObj) == 2 && (Gia_ObjRefNum(p, Gia_ObjFanin0(pObj)) == 1 || Gia_ObjRefNum(p, Gia_ObjFanin1(pObj)) == 1)) ||
+ Vec_IntSize(p->vSuper) > STR_SUPER )
+ {
+ Vec_IntPush( p->vSuper, Gia_ObjToLit(p, pObj) );
+ return;
+ }
+ Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild0(pObj) );
+ Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild1(pObj) );
+}
+static inline void Gia_ManSuperCollect( Gia_Man_t * p, Gia_Obj_t * pObj )
+{
+ if ( p->vSuper == NULL )
+ p->vSuper = Vec_IntAlloc( STR_SUPER );
+ else
+ Vec_IntClear( p->vSuper );
+ if ( Gia_ObjIsXor(pObj) )
+ {
+ assert( !Gia_ObjFaninC0(pObj) && !Gia_ObjFaninC1(pObj) );
+ Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin0(pObj) );
+ Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin1(pObj) );
+ Vec_IntSort( p->vSuper, 0 );
+ Gia_ManSimplifyXor( p->vSuper );
+ }
+ else if ( Gia_ObjIsAndReal(p, pObj) )
+ {
+ Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild0(pObj) );
+ Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild1(pObj) );
+ Vec_IntSort( p->vSuper, 0 );
+ Gia_ManSimplifyAnd( p->vSuper );
+ }
+ else assert( 0 );
+ assert( Vec_IntSize(p->vSuper) > 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Constructs AIG ordered for balancing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Str_ManNormalize_rec( Str_Ntk_t * pNtk, Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Wec_t * vGroups, Vec_Int_t * vRoots )
+{
+ int i, k, iVar, iLit, iBeg, iEnd;
+ if ( ~pObj->Value )
+ return;
+ pObj->Value = 0;
+ assert( Gia_ObjIsAnd(pObj) );
+ if ( Gia_ObjIsMux(p, pObj) )
+ {
+ Vec_Int_t * vGroup;
+ Gia_Obj_t * pRoot, * pMux;
+ int pFanins[3];
+ if ( Vec_IntEntry(vRoots, Gia_ObjId(p, pObj)) == -1 )
+ {
+ Str_ManNormalize_rec( pNtk, p, Gia_ObjFanin0(pObj), vGroups, vRoots );
+ Str_ManNormalize_rec( pNtk, p, Gia_ObjFanin1(pObj), vGroups, vRoots );
+ Str_ManNormalize_rec( pNtk, p, Gia_ObjFanin2(p, pObj), vGroups, vRoots );
+ pFanins[0] = Gia_ObjFanin0Copy(pObj);
+ pFanins[1] = Gia_ObjFanin1Copy(pObj);
+ pFanins[2] = Gia_ObjFanin2Copy(p, pObj);
+ if ( Abc_LitIsCompl(pFanins[2]) )
+ {
+ pFanins[2] = Abc_LitNot(pFanins[2]);
+ ABC_SWAP( int, pFanins[0], pFanins[1] );
+ }
+ pObj->Value = Str_ObjCreate( pNtk, STR_MUX, 3, pFanins );
+ return;
+ }
+ vGroup = Vec_WecEntry( vGroups, Vec_IntEntry(vRoots, Gia_ObjId(p, pObj)) );
+ // build data-inputs for each tree
+ Gia_ManForEachObjVec( vGroup, p, pRoot, i )
+ {
+ Str_MuxInputsCollect( p, pRoot, p->vSuper );
+ iBeg = Vec_IntSize( p->vStore );
+ Vec_IntAppend( p->vStore, p->vSuper );
+ iEnd = Vec_IntSize( p->vStore );
+ Vec_IntForEachEntryStartStop( p->vStore, iVar, k, iBeg, iEnd )
+ Str_ManNormalize_rec( pNtk, p, Gia_ManObj(p, iVar), vGroups, vRoots );
+ Vec_IntShrink( p->vStore, iBeg );
+ }
+ // build internal structures
+ Gia_ManForEachObjVec( vGroup, p, pRoot, i )
+ {
+ Str_MuxStructCollect( p, pRoot, p->vSuper );
+ Gia_ManForEachObjVec( p->vSuper, p, pMux, k )
+ {
+ pFanins[0] = Gia_ObjFanin0Copy(pMux);
+ pFanins[1] = Gia_ObjFanin1Copy(pMux);
+ pFanins[2] = Gia_ObjFanin2Copy(p, pMux);
+ if ( Abc_LitIsCompl(pFanins[2]) )
+ {
+ pFanins[2] = Abc_LitNot(pFanins[2]);
+ ABC_SWAP( int, pFanins[0], pFanins[1] );
+ }
+ pMux->Value = Str_ObjCreate( pNtk, STR_MUX, 3, pFanins );
+ }
+ assert( ~pRoot->Value );
+ // set mapping
+ Gia_ManForEachObjVec( p->vSuper, p, pMux, k )
+ Str_NtkObj(pNtk, Abc_Lit2Var(pMux->Value))->iTop = Abc_Lit2Var(pRoot->Value);
+ pNtk->nTrees++;
+ }
+ assert( ~pObj->Value );
+ // set mapping
+ pObj = Gia_ManObj( p, Vec_IntEntryLast(vGroup) );
+ Gia_ManForEachObjVec( vGroup, p, pRoot, i )
+ Str_NtkObj(pNtk, Abc_Lit2Var(pRoot->Value))->iTop = Abc_Lit2Var(pObj->Value);
+ pNtk->nGroups++;
+ //printf( "%d x %d ", Vec_IntSize(vGroup), Vec_IntSize(p->vSuper) );
+ return;
+ }
+ // find supergate
+ Gia_ManSuperCollect( p, pObj );
+ // save entries
+ iBeg = Vec_IntSize( p->vStore );
+ Vec_IntAppend( p->vStore, p->vSuper );
+ iEnd = Vec_IntSize( p->vStore );
+ // call recursively
+ Vec_IntForEachEntryStartStop( p->vStore, iLit, i, iBeg, iEnd )
+ {
+ Gia_Obj_t * pTemp = Gia_ManObj( p, Abc_Lit2Var(iLit) );
+ Str_ManNormalize_rec( pNtk, p, pTemp, vGroups, vRoots );
+ Vec_IntWriteEntry( p->vStore, i, Abc_LitNotCond(pTemp->Value, Abc_LitIsCompl(iLit)) );
+ }
+ assert( Vec_IntSize(p->vStore) == iEnd );
+ // consider general case
+ pObj->Value = Str_ObjCreate( pNtk, Gia_ObjIsXor(pObj) ? STR_XOR : STR_AND, iEnd-iBeg, Vec_IntEntryP(p->vStore, iBeg) );
+ Vec_IntShrink( p->vStore, iBeg );
+}
+Str_Ntk_t * Str_ManNormalizeInt( Gia_Man_t * p, Vec_Wec_t * vGroups, Vec_Int_t * vRoots )
+{
+ Str_Ntk_t * pNtk;
+ Gia_Obj_t * pObj;
+ int i, iFanin;
+ assert( p->pMuxes != NULL );
+ if ( p->vSuper == NULL )
+ p->vSuper = Vec_IntAlloc( STR_SUPER );
+ if ( p->vStore == NULL )
+ p->vStore = Vec_IntAlloc( STR_SUPER );
+ Gia_ManFillValue( p );
+ pNtk = Str_NtkCreate( Gia_ManObjNum(p), 1 + Gia_ManCoNum(p) + 2 * Gia_ManAndNum(p) + Gia_ManMuxNum(p) );
+ Gia_ManConst0(p)->Value = 0;
+ Gia_ManForEachObj1( p, pObj, i )
+ {
+ if ( Gia_ObjIsCi(pObj) )
+ pObj->Value = Str_ObjCreate( pNtk, STR_PI, 0, NULL );
+ else if ( Gia_ObjIsCo(pObj) )
+ {
+ Str_ManNormalize_rec( pNtk, p, Gia_ObjFanin0(pObj), vGroups, vRoots );
+ iFanin = Gia_ObjFanin0Copy(pObj);
+ pObj->Value = Str_ObjCreate( pNtk, STR_PO, 1, &iFanin );
+ }
+ }
+ assert( pNtk->nObjs <= Gia_ManObjNum(p) );
+ return pNtk;
+}
+Str_Ntk_t * Str_ManNormalize( Gia_Man_t * p )
+{
+ Str_Ntk_t * pNtk;
+ Gia_Man_t * pMuxes = Gia_ManDupMuxes( p, 5 );
+ Vec_Wec_t * vGroups = Str_ManDeriveTrees( pMuxes );
+ Vec_Int_t * vRoots;
+ Str_ManCheckOverlap( pMuxes, vGroups );
+ vRoots = Str_ManCreateRoots( vGroups, Gia_ManObjNum(pMuxes) );
+ pNtk = Str_ManNormalizeInt( pMuxes, vGroups, vRoots );
+ Gia_ManCleanMark0( pMuxes );
+ Gia_ManStop( pMuxes );
+ Vec_IntFree( vRoots );
+ Vec_WecFree( vGroups );
+ return pNtk;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Delay computation]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Str_Delay2( int d0, int d1, int nLutSize )
+{
+ int n, d = Abc_MaxInt( d0 >> 4, d1 >> 4 );
+ n = (d == (d0 >> 4)) ? (d0 & 15) : 1;
+ n += (d == (d1 >> 4)) ? (d1 & 15) : 1;
+ return (d << 4) + (n > nLutSize ? 18 : n);
+}
+static inline int Str_Delay3( int d0, int d1, int d2, int nLutSize )
+{
+ int n, d = Abc_MaxInt( Abc_MaxInt(d0 >> 4, d1 >> 4), d2 >> 4 );
+ n = (d == (d0 >> 4)) ? (d0 & 15) : 1;
+ n += (d == (d1 >> 4)) ? (d1 & 15) : 1;
+ n += (d == (d2 >> 4)) ? (d2 & 15) : 1;
+ return (d << 4) + (n > nLutSize ? 19 : n);
+}
+static inline int Str_ObjDelay( Gia_Man_t * pNew, int iObj, int nLutSize, Vec_Int_t * vDelay )
+{
+ int Delay = Vec_IntEntry( vDelay, iObj );
+ if ( Delay == 0 )
+ {
+ if ( Gia_ObjIsMuxId(pNew, iObj) )
+ {
+ int d0 = Vec_IntEntry( vDelay, Gia_ObjFaninId0(Gia_ManObj(pNew, iObj), iObj) );
+ int d1 = Vec_IntEntry( vDelay, Gia_ObjFaninId1(Gia_ManObj(pNew, iObj), iObj) );
+ int d2 = Vec_IntEntry( vDelay, Gia_ObjFaninId2(pNew, iObj) );
+ Delay = Str_Delay3( d0, d1, d2, nLutSize );
+ }
+ else
+ {
+ int d0 = Vec_IntEntry( vDelay, Gia_ObjFaninId0(Gia_ManObj(pNew, iObj), iObj) );
+ int d1 = Vec_IntEntry( vDelay, Gia_ObjFaninId1(Gia_ManObj(pNew, iObj), iObj) );
+ Delay = Str_Delay2( d0, d1, nLutSize );
+ }
+ Vec_IntWriteEntry( vDelay, iObj, Delay );
+ }
+ return Delay;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Transposing 64-bit matrix.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void transpose64( word A[64] )
+{
+ int j, k;
+ word t, m = 0x00000000FFFFFFFF;
+ for ( j = 32; j != 0; j = j >> 1, m = m ^ (m << j) )
+ {
+ for ( k = 0; k < 64; k = (k + j + 1) & ~j )
+ {
+ t = (A[k] ^ (A[k+j] >> j)) & m;
+ A[k] = A[k] ^ t;
+ A[k+j] = A[k+j] ^ (t << j);
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Perform affinity computation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Str_ManNum( Gia_Man_t * p, int iObj ) { return Vec_IntEntry(&p->vCopies, iObj); }
+static inline void Str_ManSetNum( Gia_Man_t * p, int iObj, int Num ) { Vec_IntWriteEntry(&p->vCopies, iObj, Num); }
+
+int Str_ManVectorAffinity( Gia_Man_t * p, Vec_Int_t * vSuper, Vec_Int_t * vDelay, word Matrix[256], int nLimit )
+{
+ int fVerbose = 0;
+ int Levels[256];
+ int nSize = Vec_IntSize(vSuper);
+ int Prev = nSize, nLevels = 1;
+ int i, k, iLit, iFanin, nSizeNew;
+ word Mask;
+ assert( nSize > 2 );
+ if ( nSize > 64 )
+ {
+ for ( i = 0; i < 64; i++ )
+ Matrix[i] = 0;
+ return 0;
+ }
+ // mark current nodes
+ Gia_ManIncrementTravId( p );
+ Vec_IntForEachEntry( vSuper, iLit, i )
+ {
+ Gia_ObjSetTravIdCurrentId( p, Abc_Lit2Var(iLit) );
+ Str_ManSetNum( p, Abc_Lit2Var(iLit), i );
+ Matrix[i] = ((word)1) << (63-i);
+ Levels[i] = 0;
+ }
+ // collect 64 nodes
+ Vec_IntForEachEntry( vSuper, iLit, i )
+ {
+ Gia_Obj_t * pObj = Gia_ManObj( p, Abc_Lit2Var(iLit) );
+ if ( Gia_ObjIsAnd(pObj) )
+ {
+ for ( k = 0; k < 2; k++ )
+ {
+ iFanin = k ? Gia_ObjFaninId1p(p, pObj) : Gia_ObjFaninId0p(p, pObj);
+ if ( !Gia_ObjIsTravIdCurrentId(p, iFanin) )
+ {
+ if ( Vec_IntSize(vSuper) == nLimit )
+ break;
+ Gia_ObjSetTravIdCurrentId( p, iFanin );
+ Matrix[Vec_IntSize(vSuper)] = 0;
+ Levels[Vec_IntSize(vSuper)] = nLevels;
+ Str_ManSetNum( p, iFanin, Vec_IntSize(vSuper) );
+ Vec_IntPush( vSuper, Abc_Var2Lit(iFanin, 0) );
+ }
+ Matrix[Str_ManNum(p, iFanin)] |= Matrix[i];
+ }
+ }
+ if ( Gia_ObjIsMux(p, pObj) )
+ {
+ iFanin = Gia_ObjFaninId2p(p, pObj);
+ if ( !Gia_ObjIsTravIdCurrentId(p, iFanin) )
+ {
+ if ( Vec_IntSize(vSuper) == nLimit )
+ break;
+ Gia_ObjSetTravIdCurrentId( p, iFanin );
+ Matrix[Vec_IntSize(vSuper)] = 0;
+ Levels[Vec_IntSize(vSuper)] = nLevels;
+ Str_ManSetNum( p, iFanin, Vec_IntSize(vSuper) );
+ Vec_IntPush( vSuper, Abc_Var2Lit(iFanin, 0) );
+ }
+ Matrix[Str_ManNum(p, iFanin)] |= Matrix[i];
+ }
+ if ( Prev == i )
+ Prev = Vec_IntSize(vSuper), nLevels++;
+ if ( nLevels == 8 )
+ break;
+ }
+
+ // remove those that have all 1s or only one 1
+ Mask = (~(word)0) << (64 - nSize);
+ for ( k = i = 0; i < Vec_IntSize(vSuper); i++ )
+ {
+ assert( Matrix[i] );
+ if ( (Matrix[i] & (Matrix[i] - 1)) == 0 )
+ continue;
+ if ( Matrix[i] == Mask )
+ continue;
+ Matrix[k] = Matrix[i];
+ Levels[k] = Levels[i];
+ k++;
+ if ( k == 64 )
+ break;
+ }
+ // clean the remaining ones
+ for ( i = k; i < 64; i++ )
+ Matrix[i] = 0;
+ nSizeNew = k;
+ if ( nSizeNew == 0 )
+ {
+ Vec_IntShrink( vSuper, nSize );
+ return 0;
+ }
+/*
+ // report
+ if ( fVerbose && nSize > 20 )
+ {
+ for ( i = 0; i < nSizeNew; i++ )
+ Extra_PrintBinary( stdout, Matrix+i, 64 ), printf( "\n" );
+ printf( "\n" );
+ }
+*/
+ transpose64( Matrix );
+
+ // report
+ if ( fVerbose && nSize > 10 )
+ {
+ printf( "Gate inputs = %d. Collected fanins = %d. All = %d. Good = %d. Levels = %d\n",
+ nSize, Vec_IntSize(vSuper) - nSize, Vec_IntSize(vSuper), nSizeNew, nLevels );
+ printf( " " );
+ for ( i = 0; i < nSizeNew; i++ )
+ printf( "%d", Levels[i] );
+ printf( "\n" );
+ for ( i = 0; i < nSize; i++ )
+ {
+ printf( "%6d : ", Abc_Lit2Var(Vec_IntEntry(vSuper, i)) );
+ printf( "%3d ", Vec_IntEntry(vDelay, i) >> 4 );
+ printf( "%3d ", Vec_IntEntry(vDelay, i) & 15 );
+// Extra_PrintBinary( stdout, Matrix+i, 64 ), printf( "\n" );
+ }
+ i = 0;
+ }
+ Vec_IntShrink( vSuper, nSize );
+ return nSizeNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count 1s.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Str_CountBits( word i )
+{
+ if ( i == 0 )
+ return 0;
+ i = (i & (i - 1));
+ if ( i == 0 )
+ return 1;
+ i = (i & (i - 1));
+ if ( i == 0 )
+ return 2;
+ i = i - ((i >> 1) & 0x5555555555555555);
+ i = (i & 0x3333333333333333) + ((i >> 2) & 0x3333333333333333);
+ i = ((i + (i >> 4)) & 0x0F0F0F0F0F0F0F0F);
+ return (i*(0x0101010101010101))>>56;
+}
+
+static inline void Str_PrintState( int * pCost, int * pSuper, word * pMatrix, int nSize )
+{
+ int i;
+ for ( i = 0; i < nSize; i++ )
+ {
+ printf( "%6d : ", i );
+ printf( "%6d : ", Abc_Lit2Var(pSuper[i]) );
+ printf( "%3d ", pCost[i] >> 4 );
+ printf( "%3d ", pCost[i] & 15 );
+// Extra_PrintBinary( stdout, pMatrix+i, 64 ), printf( "\n" );
+ }
+ printf( "\n" );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Perform balancing.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Str_NtkBalanceMulti2( Gia_Man_t * pNew, Str_Ntk_t * p, Str_Obj_t * pObj, Vec_Int_t * vDelay, int nLutSize )
+{
+ int k;
+ pObj->iCopy = (pObj->Type == STR_AND);
+ for ( k = 0; k < (int)pObj->nFanins; k++ )
+ {
+ if ( pObj->Type == STR_AND )
+ pObj->iCopy = Gia_ManHashAnd( pNew, pObj->iCopy, Str_ObjFaninCopy(p, pObj, k) );
+ else
+ pObj->iCopy = Gia_ManHashXorReal( pNew, pObj->iCopy, Str_ObjFaninCopy(p, pObj, k) );
+ Str_ObjDelay( pNew, Abc_Lit2Var(pObj->iCopy), nLutSize, vDelay );
+ }
+}
+
+int Str_NtkBalanceTwo( Gia_Man_t * pNew, Str_Ntk_t * p, Str_Obj_t * pObj, int i, int j, Vec_Int_t * vDelay, int * pCost, int * pSuper, word * pMatrix, int nSize, int nLutSize, int CostBest )
+{
+ int k, iLitRes, Delay;
+ assert( i < j );
+// printf( "Merging node %d and %d\n", i, j );
+ if ( pObj->Type == STR_AND )
+ iLitRes = Gia_ManHashAnd( pNew, pSuper[i], pSuper[j] );
+ else
+ iLitRes = Gia_ManHashXorReal( pNew, pSuper[i], pSuper[j] );
+ Delay = Str_ObjDelay( pNew, Abc_Lit2Var(iLitRes), nLutSize, vDelay );
+ // update
+ pCost[i] = Delay;
+ pSuper[i] = iLitRes;
+ pMatrix[i] |= pMatrix[j];
+// assert( (pCost[i] & 15) == CostBest || CostBest == -1 );
+ // remove entry j
+ nSize--;
+ for ( k = j; k < nSize; k++ )
+ {
+ pCost[k] = pCost[k+1];
+ pSuper[k] = pSuper[k+1];
+ pMatrix[k] = pMatrix[k+1];
+ }
+ // move up the first one
+ nSize--;
+ for ( k = 0; k < nSize; k++ )
+ {
+ if ( pCost[k] <= pCost[k+1] )
+ break;
+ ABC_SWAP( int, pCost[k], pCost[k+1] );
+ ABC_SWAP( int, pSuper[k], pSuper[k+1] );
+ ABC_SWAP( word, pMatrix[k], pMatrix[k+1] );
+ }
+ return iLitRes;
+}
+
+void Str_NtkBalanceMulti( Gia_Man_t * pNew, Str_Ntk_t * p, Str_Obj_t * pObj, Vec_Int_t * vDelay, int nLutSize )
+{
+ word pMatrix[256];
+ int Limit = 256;
+ Vec_Int_t * vSuper = pNew->vSuper;
+ Vec_Int_t * vCosts = pNew->vStore;
+ int * pSuper = Vec_IntArray(vSuper);
+ int * pCost = Vec_IntArray(vCosts);
+ int k, iLit, MatrixSize = 0;
+ assert( Limit <= Vec_IntCap(vSuper) );
+ assert( Limit <= Vec_IntCap(vCosts) );
+
+ // collect nodes
+ Vec_IntClear( vSuper );
+ for ( k = 0; k < (int)pObj->nFanins; k++ )
+ Vec_IntPush( vSuper, Str_ObjFaninCopy(p, pObj, k) );
+ Vec_IntSort( vSuper, 0 );
+ if ( pObj->Type == STR_AND )
+ Gia_ManSimplifyAnd( vSuper );
+ else
+ Gia_ManSimplifyXor( vSuper );
+ assert( Vec_IntSize(vSuper) > 0 );
+ if ( Vec_IntSize(vSuper) == 1 )
+ {
+ pObj->iCopy = Vec_IntEntry(vSuper, 0);
+ return;
+ }
+ if ( Vec_IntSize(vSuper) == 2 )
+ {
+ pObj->iCopy = Str_NtkBalanceTwo( pNew, p, pObj, 0, 1, vDelay, pCost, pSuper, pMatrix, 2, nLutSize, -1 );
+ return;
+ }
+
+ // sort by cost
+ Vec_IntClear( vCosts );
+ Vec_IntForEachEntry( vSuper, iLit, k )
+ Vec_IntPush( vCosts, Vec_IntEntry(vDelay, Abc_Lit2Var(iLit)) );
+ Vec_IntSelectSortCost2( pSuper, Vec_IntSize(vSuper), pCost );
+
+ // compute affinity
+ if ( Vec_IntSize(vSuper) < 64 )
+ MatrixSize = Str_ManVectorAffinity( pNew, vSuper, vCosts, pMatrix, Limit );
+
+ // start the new product
+ while ( Vec_IntSize(vSuper) > 2 )
+ {
+ // pair the first entry with another one on the same level
+ int i, iStop, iBest,iBest2;
+ int CostNew, CostBest, CostBest2;
+ int OccurNew, OccurBest, OccurBest2;
+
+ if ( Vec_IntSize(vSuper) > 64 )
+ {
+ Str_NtkBalanceTwo( pNew, p, pObj, 0, 1, vDelay, pCost, pSuper, pMatrix, Vec_IntSize(vSuper), nLutSize, -1 );
+ vSuper->nSize--;
+ vCosts->nSize--;
+ continue;
+ }
+
+ // compute affinity
+ if ( Vec_IntSize(vSuper) == 64 )
+ MatrixSize = Str_ManVectorAffinity( pNew, vSuper, vCosts, pMatrix, Limit );
+ assert( Vec_IntSize(vSuper) <= 64 );
+// Str_PrintState( pCost, pSuper, pMatrix, Vec_IntSize(vSuper) );
+
+ // if the first two are PIs group them
+ if ( pCost[0] == 17 && pCost[1] == 17 )
+ {
+ Str_NtkBalanceTwo( pNew, p, pObj, 0, 1, vDelay, pCost, pSuper, pMatrix, Vec_IntSize(vSuper), nLutSize, 2 );
+ vSuper->nSize--;
+ vCosts->nSize--;
+ continue;
+ }
+
+ // find the end of the level
+ for ( iStop = 0; iStop < Vec_IntSize(vSuper); iStop++ )
+ if ( (pCost[iStop] >> 4) != (pCost[0] >> 4) )
+ break;
+ // if there is only one this level, pair it with the best match in the next level
+ if ( iStop == 1 )
+ {
+ iBest = iStop, OccurBest = Str_CountBits(pMatrix[0] & pMatrix[iStop]);
+ for ( i = iStop + 1; i < Vec_IntSize(vSuper); i++ )
+ {
+ if ( (pCost[i] >> 4) != (pCost[iStop] >> 4) )
+ break;
+ OccurNew = Str_CountBits(pMatrix[0] & pMatrix[i]);
+ if ( OccurBest < OccurNew )
+ iBest = i, OccurBest = OccurNew;
+ }
+ assert( iBest > 0 && iBest < Vec_IntSize(vSuper) );
+ Str_NtkBalanceTwo( pNew, p, pObj, 0, iBest, vDelay, pCost, pSuper, pMatrix, Vec_IntSize(vSuper), nLutSize, -1 );
+ vSuper->nSize--;
+ vCosts->nSize--;
+ continue;
+ }
+ // pair the first entry with another one on the same level
+ iBest = -1; CostBest = -1; OccurBest2 = -1; OccurBest = -1;
+ for ( i = 1; i < iStop; i++ )
+ {
+ CostNew = (pCost[0] & 15) + (pCost[i] & 15);
+ if ( CostNew > nLutSize )
+ continue;
+ OccurNew = Str_CountBits(pMatrix[0] & pMatrix[i]);
+ if ( CostBest < CostNew || (CostBest == CostNew && OccurBest < OccurNew) )
+ CostBest = CostNew, iBest = i, OccurBest = OccurNew;
+ }
+ // if the best found is perfect, take it
+ if ( CostBest == nLutSize )
+ {
+ assert( iBest > 0 && iBest < Vec_IntSize(vSuper) );
+ Str_NtkBalanceTwo( pNew, p, pObj, 0, iBest, vDelay, pCost, pSuper, pMatrix, Vec_IntSize(vSuper), nLutSize, CostBest );
+ vSuper->nSize--;
+ vCosts->nSize--;
+ continue;
+ }
+ // find the best pair on this level
+ iBest = iBest2 = -1; CostBest = CostBest2 = -1, OccurBest = OccurBest2 = -1;
+ for ( i = 0; i < iStop; i++ )
+ for ( k = i+1; k < iStop; k++ )
+ {
+ CostNew = (pCost[i] & 15) + (pCost[k] & 15);
+ OccurNew = Str_CountBits(pMatrix[i] & pMatrix[k]);
+ if ( CostNew <= nLutSize ) // the same level
+ {
+ if ( OccurBest < OccurNew || (OccurBest == OccurNew && CostBest < CostNew ))
+ CostBest = CostNew, iBest = (i << 16) | k, OccurBest = OccurNew;
+ }
+ else // overflow to the next level
+ {
+ if ( OccurBest2 < OccurNew || (OccurBest2 == OccurNew && CostBest2 < CostNew) )
+ CostBest2 = CostNew, iBest2 = (i << 16) | k, OccurBest2 = OccurNew;
+ }
+ }
+ if ( iBest >= 0 )
+ {
+ assert( iBest > 0 );
+ Str_NtkBalanceTwo( pNew, p, pObj, iBest>>16, iBest&0xFFFF, vDelay, pCost, pSuper, pMatrix, Vec_IntSize(vSuper), nLutSize, CostBest );
+ vSuper->nSize--;
+ vCosts->nSize--;
+ continue;
+ }
+ // take any remaining pair
+ assert( iBest2 > 0 );
+ Str_NtkBalanceTwo( pNew, p, pObj, iBest2>>16, iBest2&0xFFFF, vDelay, pCost, pSuper, pMatrix, Vec_IntSize(vSuper), nLutSize, -1 );
+ vSuper->nSize--;
+ vCosts->nSize--;
+ continue;
+ }
+ pObj->iCopy = Str_NtkBalanceTwo( pNew, p, pObj, 0, 1, vDelay, pCost, pSuper, pMatrix, 2, nLutSize, -1 );
+
+/*
+ // simple
+ pObj->iCopy = (pObj->Type == STR_AND);
+ for ( k = 0; k < Vec_IntSize(vSuper); k++ )
+ {
+ if ( pObj->Type == STR_AND )
+ pObj->iCopy = Gia_ManHashAnd( pNew, pObj->iCopy, Vec_IntEntry(vSuper, k) );
+ else
+ pObj->iCopy = Gia_ManHashXorReal( pNew, pObj->iCopy, Vec_IntEntry(vSuper, k) );
+ Str_ObjDelay( pNew, Abc_Lit2Var(pObj->iCopy), nLutSize, vDelay );
+ }
+*/
+}
+void Str_NtkBalanceMux( Gia_Man_t * pNew, Str_Ntk_t * p, Str_Obj_t * pObj, Vec_Int_t * vDelay, int nLutSize, int nGroups, int nMuxes, int fRecursive, int fOptArea, int fVerbose )
+{
+ extern int Str_MuxRestructure( Gia_Man_t * pNew, Str_Ntk_t * pNtk, int iMux, int nMuxes, Vec_Int_t * vDelay, int nLutSize, int fRecursive, int fOptArea, int fVerbose );
+ int n, m, iRes, fUseRestruct = 1;
+ if ( fUseRestruct )
+ {
+ for ( n = 0; n < nGroups; n++ )
+ {
+ iRes = Str_MuxRestructure( pNew, p, Str_ObjId(p, pObj), nMuxes, vDelay, nLutSize, fRecursive, fOptArea, fVerbose );
+ if ( iRes == -1 )
+ {
+ for ( m = 0; m < nMuxes; m++, pObj++ )
+ {
+ pObj->iCopy = Gia_ManHashMuxReal( pNew, Str_ObjFaninCopy(p, pObj, 2), Str_ObjFaninCopy(p, pObj, 1), Str_ObjFaninCopy(p, pObj, 0) );
+ Str_ObjDelay( pNew, Abc_Lit2Var(pObj->iCopy), nLutSize, vDelay );
+ }
+ }
+ else
+ {
+ pObj += nMuxes - 1;
+ pObj->iCopy = iRes;
+ pObj++;
+ }
+ }
+ }
+ else
+ {
+ for ( n = 0; n < nGroups * nMuxes; n++, pObj++ )
+ {
+ pObj->iCopy = Gia_ManHashMuxReal( pNew, Str_ObjFaninCopy(p, pObj, 2), Str_ObjFaninCopy(p, pObj, 1), Str_ObjFaninCopy(p, pObj, 0) );
+ Str_ObjDelay( pNew, Abc_Lit2Var(pObj->iCopy), nLutSize, vDelay );
+ }
+ }
+}
+Gia_Man_t * Str_NtkBalance( Gia_Man_t * pGia, Str_Ntk_t * p, int nLutSize, int fUseMuxes, int fRecursive, int fOptArea, int fVerbose )
+{
+ Gia_Man_t * pNew, * pTemp;
+ Vec_Int_t * vDelay;
+ Str_Obj_t * pObj;
+ int nGroups, nMuxes, CioId;
+ int arrTime, Delay = 0;
+ assert( nLutSize < 16 );
+ assert( pGia->pMuxes == NULL );
+ pNew = Gia_ManStart( Gia_ManObjNum(pGia) );
+ pNew->pName = Abc_UtilStrsav( pGia->pName );
+ pNew->pSpec = Abc_UtilStrsav( pGia->pSpec );
+ pNew->pMuxes = ABC_CALLOC( unsigned, pNew->nObjsAlloc );
+ Vec_IntFill( &pNew->vCopies, pNew->nObjsAlloc, -1 );
+ if ( pNew->vSuper == NULL )
+ pNew->vSuper = Vec_IntAlloc( 1000 );
+ if ( pNew->vStore == NULL )
+ pNew->vStore = Vec_IntAlloc( 1000 );
+ vDelay = Vec_IntStart( pNew->nObjsAlloc );
+ Gia_ManHashStart( pNew );
+ if ( pGia->pManTime != NULL ) // Tim_Man with unit delay 16
+ {
+ Tim_ManInitPiArrivalAll( (Tim_Man_t *)pGia->pManTime, 17 );
+ Tim_ManIncrementTravId( (Tim_Man_t *)pGia->pManTime );
+ }
+ Str_NtkManForEachObj( p, pObj )
+ {
+ if ( pObj->Type == STR_PI )
+ {
+ pObj->iCopy = Gia_ManAppendCi( pNew );
+ arrTime = 17;
+ if ( pGia->pManTime != NULL )
+ {
+ CioId = Gia_ObjCioId( Gia_ManObj(pNew, Abc_Lit2Var(pObj->iCopy)) );
+ arrTime = (int)Tim_ManGetCiArrival( (Tim_Man_t *)pGia->pManTime, CioId );
+ }
+ Vec_IntWriteEntry( vDelay, Abc_Lit2Var(pObj->iCopy), arrTime );
+ }
+ else if ( pObj->Type == STR_AND || pObj->Type == STR_XOR )
+ Str_NtkBalanceMulti( pNew, p, pObj, vDelay, nLutSize );
+ else if ( pObj->Type == STR_MUX && pObj->iTop >= 0 && fUseMuxes )
+ {
+ Str_ObjReadGroup( p, pObj, &nGroups, &nMuxes );
+ assert( nGroups * nMuxes >= 2 );
+ Str_NtkBalanceMux( pNew, p, pObj, vDelay, nLutSize, nGroups, nMuxes, fRecursive, fOptArea, fVerbose );
+ pObj += nGroups * nMuxes - 1;
+ }
+ else if ( pObj->Type == STR_MUX )
+ {
+ pObj->iCopy = Gia_ManHashMuxReal( pNew, Str_ObjFaninCopy(p, pObj, 2), Str_ObjFaninCopy(p, pObj, 1), Str_ObjFaninCopy(p, pObj, 0) );
+ Str_ObjDelay( pNew, Abc_Lit2Var(pObj->iCopy), nLutSize, vDelay );
+ }
+ else if ( pObj->Type == STR_PO )
+ {
+ pObj->iCopy = Gia_ManAppendCo( pNew, Str_ObjFaninCopy(p, pObj, 0) );
+ arrTime = Vec_IntEntry(vDelay, Abc_Lit2Var(Str_ObjFaninCopy(p, pObj, 0)) );
+ Delay = Abc_MaxInt( Delay, arrTime );
+ if ( pGia->pManTime != NULL )
+ {
+ CioId = Gia_ObjCioId( Gia_ManObj(pNew, Abc_Lit2Var(pObj->iCopy)) );
+ Tim_ManSetCoArrival( (Tim_Man_t *)pGia->pManTime, CioId, (float)arrTime );
+ }
+ }
+ else if ( pObj->Type == STR_CONST0 )
+ pObj->iCopy = 0, Vec_IntWriteEntry(vDelay, 0, 17);
+ else assert( 0 );
+ }
+ if ( fVerbose )
+ printf( "Max delay = %d. Old objs = %d. New objs = %d.\n", Delay >> 4, Gia_ManObjNum(pGia), Gia_ManObjNum(pNew) );
+ Vec_IntFree( vDelay );
+ ABC_FREE( pNew->vCopies.pArray );
+ Gia_ManHashStop( pNew );
+ Gia_ManSetRegNum( pNew, Gia_ManRegNum(pGia) );
+ pNew = Gia_ManDupNoMuxes( pTemp = pNew );
+ Gia_ManStop( pTemp );
+// if ( pGia->pManTime != NULL )
+// pNew->pManTime = Tim_ManDup( (Tim_Man_t *)pGia->pManTime, 0 );
+ return pNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Test normalization procedure.]
Description []
@@ -45,9 +1376,484 @@ ABC_NAMESPACE_IMPL_START
***********************************************************************/
Gia_Man_t * Gia_ManLutBalance( Gia_Man_t * p, int nLutSize, int fUseMuxes, int fRecursive, int fOptArea, int fVerbose )
{
- return Gia_ManDup(p);
+ Str_Ntk_t * pNtk;
+ Gia_Man_t * pNew;
+ abctime clk = Abc_Clock();
+ if ( p->pManTime && Tim_ManBoxNum(p->pManTime) && Gia_ManIsNormalized(p) )
+ {
+ Tim_Man_t * pTimOld = (Tim_Man_t *)p->pManTime;
+ p->pManTime = Tim_ManDup( pTimOld, 16 );
+ pNew = Gia_ManDupUnnormalize( p );
+ if ( pNew == NULL )
+ return NULL;
+ Gia_ManTransferTiming( pNew, p );
+ p = pNew;
+ // optimize
+ pNtk = Str_ManNormalize( p );
+ pNew = Str_NtkBalance( p, pNtk, nLutSize, fUseMuxes, fRecursive, fOptArea, fVerbose );
+ Gia_ManTransferTiming( pNew, p );
+ Gia_ManStop( p );
+ // normalize
+ pNew = Gia_ManDupNormalize( p = pNew );
+ Gia_ManTransferTiming( pNew, p );
+ Gia_ManStop( p );
+ // cleanup
+ Tim_ManStop( (Tim_Man_t *)pNew->pManTime );
+ pNew->pManTime = pTimOld;
+ assert( Gia_ManIsNormalized(pNew) );
+ }
+ else
+ {
+ pNtk = Str_ManNormalize( p );
+ // Str_NtkPrintGroups( pNtk );
+ pNew = Str_NtkBalance( p, pNtk, nLutSize, fUseMuxes, fRecursive, fOptArea, fVerbose );
+ Gia_ManTransferTiming( pNew, p );
+ }
+ if ( fVerbose )
+ Str_NtkPs( pNtk, Abc_Clock() - clk );
+ Str_NtkDelete( pNtk );
+ return pNew;
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Perform MUX restructuring.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+typedef struct Str_Edg_t_ Str_Edg_t;
+struct Str_Edg_t_
+{
+ int Fan; // fanin ID
+ int fCompl; // fanin complement
+ int FanDel; // fanin delay
+ int Copy; // fanin copy
+};
+
+typedef struct Str_Mux_t_ Str_Mux_t; // 64 bytes
+struct Str_Mux_t_
+{
+ int Id; // node ID
+ int Delay; // node delay
+ int Copy; // node copy
+ int nLutSize; // LUT size
+ Str_Edg_t Edge[3]; // fanins
+};
+
+static inline Str_Mux_t * Str_MuxFanin( Str_Mux_t * pMux, int i ) { return pMux - pMux->Id + pMux->Edge[i].Fan; }
+static inline int Str_MuxHasFanin( Str_Mux_t * pMux, int i ) { return pMux->Edge[i].Fan > 0 && Str_MuxFanin(pMux, i)->Copy != -2; }
+
+void Str_MuxDelayPrint_rec( Str_Mux_t * pMux, int i )
+{
+ int fShowDelay = 1;
+ Str_Mux_t * pFanin;
+ if ( pMux->Edge[i].Fan <= 0 )
+ {
+ printf( "%d", -pMux->Edge[i].Fan );
+ if ( fShowDelay )
+ printf( "{%d}", pMux->Edge[i].FanDel );
+ return;
+ }
+ pFanin = Str_MuxFanin( pMux, i );
+ printf( "[ " );
+ if ( pFanin->Edge[0].fCompl )
+ printf( "!" );
+ Str_MuxDelayPrint_rec( pFanin, 0 );
+ printf( "|" );
+ if ( pFanin->Edge[1].fCompl )
+ printf( "!" );
+ Str_MuxDelayPrint_rec( pFanin, 1 );
+ printf( "(" );
+ if ( pFanin->Edge[2].fCompl )
+ printf( "!" );
+ Str_MuxDelayPrint_rec( pFanin, 2 );
+ printf( ")" );
+ printf( " ]" );
+}
+int Str_MuxDelayEdge_rec( Str_Mux_t * pMux, int i )
+{
+ if ( pMux->Edge[i].Fan > 0 )
+ {
+ Str_Mux_t * pFanin = Str_MuxFanin( pMux, i );
+ Str_MuxDelayEdge_rec( pFanin, 0 );
+ Str_MuxDelayEdge_rec( pFanin, 1 );
+ pMux->Edge[i].FanDel = Str_Delay3( pFanin->Edge[0].FanDel, pFanin->Edge[1].FanDel, pFanin->Edge[2].FanDel, pFanin->nLutSize );
+ }
+ return pMux->Edge[i].FanDel;
+}
+void Str_MuxCreate( Str_Mux_t * pTree, Str_Ntk_t * pNtk, int iMux, int nMuxes, Vec_Int_t * vDelay, int nLutSize )
+{
+ Str_Obj_t * pObj;
+ Str_Mux_t * pMux;
+ int i, k, nPis = 0;
+ assert( nMuxes >= 2 );
+ memset( pTree, 0, sizeof(Str_Mux_t) * (nMuxes + 1) );
+ pTree->nLutSize = nLutSize;
+ pTree->Edge[0].Fan = 1;
+ for ( i = 1; i <= nMuxes; i++ )
+ {
+ pMux = pTree + i;
+ pMux->Id = i;
+ pMux->nLutSize = nLutSize;
+ pMux->Delay = pMux->Copy = -1;
+ // assign fanins
+ pObj = Str_NtkObj( pNtk, iMux + nMuxes - i );
+ assert( pObj->Type == STR_MUX );
+ for ( k = 0; k < 3; k++ )
+ {
+ pMux->Edge[k].fCompl = Str_ObjFaninC(pNtk, pObj, k);
+ if ( Str_ObjFaninId(pNtk, pObj, k) >= iMux )
+ pMux->Edge[k].Fan = iMux + nMuxes - Str_ObjFaninId(pNtk, pObj, k);
+ else
+ {
+ pMux->Edge[k].Fan = -nPis++; // count external inputs, including controls
+ pMux->Edge[k].Copy = Str_ObjFanin(pNtk, pObj, k)->iCopy;
+ pMux->Edge[k].FanDel = Vec_IntEntry( vDelay, Abc_Lit2Var(pMux->Edge[k].Copy) );
+ }
+ }
+ }
+}
+int Str_MuxToGia_rec( Gia_Man_t * pNew, Str_Mux_t * pMux, int i, Vec_Int_t * vDelay )
+{
+ if ( pMux->Edge[i].Fan > 0 )
+ {
+ Str_Mux_t * pFanin = Str_MuxFanin( pMux, i );
+ int iLit0 = Str_MuxToGia_rec( pNew, pFanin, 0, vDelay );
+ int iLit1 = Str_MuxToGia_rec( pNew, pFanin, 1, vDelay );
+ assert( pFanin->Edge[2].Fan <= 0 );
+ assert( pFanin->Edge[2].fCompl == 0 );
+ pMux->Edge[i].Copy = Gia_ManHashMuxReal( pNew, pFanin->Edge[2].Copy, iLit1, iLit0 );
+ Str_ObjDelay( pNew, Abc_Lit2Var(pMux->Edge[i].Copy), pFanin->nLutSize, vDelay );
+ }
+ return Abc_LitNotCond( pMux->Edge[i].Copy, pMux->Edge[i].fCompl );
}
+void Str_MuxChangeOnce( Str_Mux_t * pTree, int * pPath, int i, int k, Str_Mux_t * pBackup, Gia_Man_t * pNew, Vec_Int_t * vDelay )
+{
+ Str_Mux_t * pSpots[3];
+ int pInds[3], MidFan, MidCom, MidDel, MidCop, c;
+ int iRes, iCond, fCompl;
+ // save backup
+ assert( i + 1 < k );
+ if ( pBackup )
+ {
+ pBackup[0] = pTree[ Abc_Lit2Var(pPath[k]) ];
+ pBackup[1] = pTree[ Abc_Lit2Var(pPath[i+1])];
+ pBackup[2] = pTree[ Abc_Lit2Var(pPath[i]) ];
+ }
+ // perform changes
+ pSpots[0] = pTree + Abc_Lit2Var(pPath[k]);
+ pSpots[1] = pTree + Abc_Lit2Var(pPath[i+1]);
+ pSpots[2] = pTree + Abc_Lit2Var(pPath[i]);
+ pInds[0] = Abc_LitIsCompl(pPath[k]);
+ pInds[1] = Abc_LitIsCompl(pPath[i+1]);
+ pInds[2] = Abc_LitIsCompl(pPath[i]);
+ // check
+ assert( pSpots[0]->Edge[pInds[0]].Fan > 0 );
+ assert( pSpots[1]->Edge[pInds[1]].Fan > 0 );
+ // collect complement
+ fCompl = 0;
+ for ( c = i+1; c < k; c++ )
+ fCompl ^= pTree[Abc_Lit2Var(pPath[c])].Edge[Abc_LitIsCompl(pPath[c])].fCompl;
+ // remember bottom side
+ MidFan = pSpots[2]->Edge[!pInds[2]].Fan;
+ MidCom = pSpots[2]->Edge[!pInds[2]].fCompl;
+ MidDel = pSpots[2]->Edge[!pInds[2]].FanDel;
+ MidCop = pSpots[2]->Edge[!pInds[2]].Copy;
+ // update bottom
+ pSpots[2]->Edge[!pInds[2]].Fan = pSpots[0]->Edge[pInds[0]].Fan;
+ pSpots[2]->Edge[!pInds[2]].fCompl = 0;
+ // update top
+ pSpots[0]->Edge[pInds[0]].Fan = pSpots[2]->Id;
+ // update middle
+ pSpots[1]->Edge[pInds[1]].Fan = MidFan;
+ pSpots[1]->Edge[pInds[1]].fCompl ^= MidCom;
+ pSpots[1]->Edge[pInds[1]].FanDel = MidDel;
+ pSpots[1]->Edge[pInds[1]].Copy = MidCop;
+ // update delay of the control
+ for ( c = i + 1; c < k; c++ )
+ pSpots[2]->Edge[2].FanDel = Str_Delay2( pSpots[2]->Edge[2].FanDel, pTree[Abc_Lit2Var(pPath[c])].Edge[2].FanDel, pTree->nLutSize );
+ if ( pNew == NULL )
+ return;
+ // create AND gates
+ iRes = 1;
+ for ( c = i; c < k; c++ )
+ {
+ assert( pTree[Abc_Lit2Var(pPath[c])].Edge[2].fCompl == 0 );
+ iCond = pTree[Abc_Lit2Var(pPath[c])].Edge[2].Copy;
+ iCond = Abc_LitNotCond( iCond, !Abc_LitIsCompl(pPath[c]) );
+ iRes = Gia_ManHashAnd( pNew, iRes, iCond );
+ Str_ObjDelay( pNew, Abc_Lit2Var(iRes), pTree->nLutSize, vDelay );
+ }
+ // complement the condition
+ pSpots[2]->Edge[2].Copy = Abc_LitNotCond( iRes, !Abc_LitIsCompl(pPath[i]) );
+ // complement the path
+ pSpots[2]->Edge[pInds[2]].fCompl ^= fCompl;
+}
+void Str_MuxChangeUndo( Str_Mux_t * pTree, int * pPath, int i, int k, Str_Mux_t * pBackup )
+{
+ pTree[ Abc_Lit2Var(pPath[k]) ] = pBackup[0];
+ pTree[ Abc_Lit2Var(pPath[i+1])] = pBackup[1];
+ pTree[ Abc_Lit2Var(pPath[i]) ] = pBackup[2];
+}
+int Str_MuxFindPathEdge_rec( Str_Mux_t * pMux, int i, int * pPath, int * pnLength )
+{
+ extern int Str_MuxFindPath_rec( Str_Mux_t * pMux, int * pPath, int * pnLength );
+ if ( pMux->Edge[i].Fan > 0 && !Str_MuxFindPath_rec(Str_MuxFanin(pMux, i), pPath, pnLength) )
+ return 0;
+ pPath[ (*pnLength)++ ] = Abc_Var2Lit(pMux->Id, i);
+ return 1;
+}
+int Str_MuxFindPath_rec( Str_Mux_t * pMux, int * pPath, int * pnLength )
+{
+ int i, DelayMax = Abc_MaxInt( pMux->Edge[0].FanDel, Abc_MaxInt(pMux->Edge[1].FanDel, pMux->Edge[2].FanDel) );
+ for ( i = 0; i < 2; i++ )
+ if ( pMux->Edge[i].FanDel == DelayMax )
+ return Str_MuxFindPathEdge_rec( pMux, i, pPath, pnLength );
+ if ( pMux->Edge[2].FanDel == DelayMax )
+ return 0;
+ assert( 0 );
+ return -1;
+}
+// return node whose both branches are non-trivial
+Str_Mux_t * Str_MuxFindBranching( Str_Mux_t * pRoot, int i )
+{
+ Str_Mux_t * pMux;
+ if ( pRoot->Edge[i].Fan <= 0 )
+ return NULL;
+ pMux = Str_MuxFanin( pRoot, i );
+ while ( 1 )
+ {
+ if ( pMux->Edge[0].Fan <= 0 && pMux->Edge[1].Fan <= 0 )
+ return NULL;
+ if ( pMux->Edge[0].Fan > 0 && pMux->Edge[1].Fan > 0 )
+ return pMux;
+ if ( pMux->Edge[0].Fan > 0 )
+ pMux = Str_MuxFanin( pMux, 0 );
+ if ( pMux->Edge[1].Fan > 0 )
+ pMux = Str_MuxFanin( pMux, 1 );
+ }
+ assert( 0 );
+ return NULL;
+}
+int Str_MuxTryOnce( Gia_Man_t * pNew, Str_Ntk_t * pNtk, Str_Mux_t * pTree, Str_Mux_t * pRoot, int Edge, Vec_Int_t * vDelay, int fVerbose )
+{
+ int pPath[500];
+ Str_Mux_t pBackup[3];
+ int Delay, DelayBest = Str_MuxDelayEdge_rec( pRoot, Edge ), DelayInit = DelayBest;
+ int i, k, nLength = 0, ForkBest = -1, nChecks = 0;
+ int RetValue = Str_MuxFindPathEdge_rec( pRoot, Edge, pPath, &nLength );
+ if ( RetValue == 0 )
+ return 0;
+ if ( fVerbose )
+ printf( "Trying node %d with path of length %d.\n", pRoot->Id, nLength );
+ for ( i = 0; i < nLength; i++ )
+ for ( k = i+2; k < nLength; k++ )
+ {
+ Str_MuxChangeOnce( pTree, pPath, i, k, pBackup, NULL, NULL );
+ Delay = Str_MuxDelayEdge_rec( pRoot, Edge );
+ Str_MuxChangeUndo( pTree, pPath, i, k, pBackup );
+ if ( DelayBest > Delay || (ForkBest > 0 && DelayBest == Delay) )
+ DelayBest = Delay, ForkBest = (i << 16) | k;
+ if ( fVerbose )
+ printf( "%2d %2d -> %3d (%3d)\n", i, k, Delay, DelayBest );
+ nChecks++;
+ }
+ if ( ForkBest == -1 )
+ {
+ if ( fVerbose )
+ printf( "Did not find!\n" );
+ return 0;
+ }
+// Str_MuxDelayPrint_rec( pRoot, Edge ); printf( "\n" );
+ Str_MuxChangeOnce( pTree, pPath, ForkBest >> 16, ForkBest & 0xFFFF, NULL, pNew, vDelay );
+// Str_MuxDelayPrint_rec( pRoot, Edge ); printf( "\n" );
+ if ( fVerbose )
+ printf( "Node %6d (%3d %3d) : Checks = %d. Delay: %d -> %d.\n",
+ pRoot->Id, ForkBest >> 16, ForkBest & 0xFFFF, nChecks, DelayInit, DelayBest );
+ if ( fVerbose )
+ printf( "\n" );
+ return 1;
+}
+int Str_MuxRestruct_rec( Gia_Man_t * pNew, Str_Ntk_t * pNtk, Str_Mux_t * pTree, Str_Mux_t * pRoot, int Edge, Vec_Int_t * vDelay, int fVerbose )
+{
+ int fChanges = 0;
+ Str_Mux_t * pMux = Str_MuxFindBranching( pRoot, Edge );
+ if ( pMux != NULL )
+ fChanges |= Str_MuxRestruct_rec( pNew, pNtk, pTree, pMux, 0, vDelay, fVerbose );
+ if ( pMux != NULL )
+ fChanges |= Str_MuxRestruct_rec( pNew, pNtk, pTree, pMux, 1, vDelay, fVerbose );
+ fChanges |= Str_MuxTryOnce( pNew, pNtk, pTree, pRoot, Edge, vDelay, fVerbose );
+ return fChanges;
+}
+int Str_MuxRestructure2( Gia_Man_t * pNew, Str_Ntk_t * pNtk, int iMux, int nMuxes, Vec_Int_t * vDelay, int nLutSize, int fVerbose )
+{
+ int Limit = 500;
+ Str_Mux_t pTree[500];
+ int Delay, Delay2, fChanges = 0;
+ if ( nMuxes >= Limit )
+ return -1;
+ assert( nMuxes < Limit );
+ Str_MuxCreate( pTree, pNtk, iMux, nMuxes, vDelay, nLutSize );
+ Delay = Str_MuxDelayEdge_rec( pTree, 0 );
+ while ( 1 )
+ {
+ if ( !Str_MuxRestruct_rec(pNew, pNtk, pTree, pTree, 0, vDelay, fVerbose) )
+ break;
+ fChanges = 1;
+ }
+ if ( !fChanges )
+ return -1;
+ Delay2 = Str_MuxDelayEdge_rec( pTree, 0 );
+// printf( "Improved delay for tree %d with %d MUXes (%d -> %d).\n", iMux, nMuxes, Delay, Delay2 );
+ pNtk->DelayGain += Delay - Delay2;
+ return Str_MuxToGia_rec( pNew, pTree, 0, vDelay );
+}
+int Str_MuxRestructure1( Gia_Man_t * pNew, Str_Ntk_t * pNtk, int iMux, int nMuxes, Vec_Int_t * vDelay, int nLutSize, int fVerbose )
+{
+ int Limit = 500;
+ Str_Mux_t pTree[500];
+ int Delay, Delay2, fChanges = 0;
+ if ( nMuxes >= Limit )
+ return -1;
+ assert( nMuxes < Limit );
+ Str_MuxCreate( pTree, pNtk, iMux, nMuxes, vDelay, nLutSize );
+ Delay = Str_MuxDelayEdge_rec( pTree, 0 );
+ while ( 1 )
+ {
+ if ( !Str_MuxTryOnce(pNew, pNtk, pTree, pTree, 0, vDelay, fVerbose) )
+ break;
+ fChanges = 1;
+ }
+ if ( !fChanges )
+ return -1;
+ Delay2 = Str_MuxDelayEdge_rec( pTree, 0 );
+// printf( "Improved delay for tree %d with %d MUXes (%d -> %d).\n", iMux, nMuxes, Delay, Delay2 );
+ pNtk->DelayGain += Delay - Delay2;
+ return Str_MuxToGia_rec( pNew, pTree, 0, vDelay );
+}
+int Str_MuxRestructure( Gia_Man_t * pNew, Str_Ntk_t * pNtk, int iMux, int nMuxes, Vec_Int_t * vDelay, int nLutSize, int fRecursive, int fOptArea, int fVerbose )
+{
+ extern int Str_MuxRestructureArea( Gia_Man_t * pNew, Str_Ntk_t * pNtk, int iMux, int nMuxes, Vec_Int_t * vDelay, int nLutSize, int fVerbose );
+ if ( fOptArea )
+ {
+ if ( nMuxes < 2 )
+ return Str_MuxRestructure1( pNew, pNtk, iMux, nMuxes, vDelay, nLutSize, fVerbose );
+ return Str_MuxRestructureArea( pNew, pNtk, iMux, nMuxes, vDelay, nLutSize, fVerbose );
+ }
+ if ( fRecursive )
+ return Str_MuxRestructure2( pNew, pNtk, iMux, nMuxes, vDelay, nLutSize, fVerbose );
+ return Str_MuxRestructure1( pNew, pNtk, iMux, nMuxes, vDelay, nLutSize, fVerbose );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Perform MUX restructuring for area.]
+
+ Description []
+
+ SideEffects []
+ SeeAlso []
+
+***********************************************************************/
+int Str_MuxRestructAreaThree( Gia_Man_t * pNew, Str_Mux_t * pMux, Vec_Int_t * vDelay, int fVerbose )
+{
+ int iRes;
+ Str_Mux_t * pFanin0 = Str_MuxFanin( pMux, 0 );
+ Str_Mux_t * pFanin1 = Str_MuxFanin( pMux, 1 );
+ assert( pMux->Copy == -1 );
+ pMux->Copy = -2;
+ if ( pFanin0->Edge[2].Copy == pFanin1->Edge[2].Copy )
+ return 0;
+ iRes = Gia_ManHashMuxReal( pNew, pMux->Edge[2].Copy, pFanin1->Edge[2].Copy, pFanin0->Edge[2].Copy );
+ Str_ObjDelay( pNew, Abc_Lit2Var(iRes), pMux->nLutSize, vDelay );
+ pFanin0->Edge[2].Copy = pFanin1->Edge[2].Copy = iRes;
+// printf( "Created triple\n" );
+ return 0;
+}
+int Str_MuxRestructArea_rec( Gia_Man_t * pNew, Str_Mux_t * pTree, Str_Mux_t * pRoot, int i, Vec_Int_t * vDelay, int fVerbose )
+{
+ int Path[4];
+ int fSkipMoving = 1;
+ Str_Mux_t * pMux, * pFanin0, * pFanin1;
+ int nMuxes0, nMuxes1;
+ if ( pRoot->Edge[i].Fan <= 0 )
+ return 0;
+ pMux = Str_MuxFanin( pRoot, i );
+ nMuxes0 = Str_MuxRestructArea_rec( pNew, pTree, pMux, 0, vDelay, fVerbose );
+ nMuxes1 = Str_MuxRestructArea_rec( pNew, pTree, pMux, 1, vDelay, fVerbose );
+ if ( nMuxes0 + nMuxes1 < 2 )
+ return 1 + nMuxes0 + nMuxes1;
+ if ( nMuxes0 + nMuxes1 == 2 )
+ {
+ if ( nMuxes0 == 2 || nMuxes1 == 2 )
+ {
+ pFanin0 = Str_MuxFanin( pMux, (int)(nMuxes1 == 2) );
+ assert( Str_MuxHasFanin(pFanin0, 0) != Str_MuxHasFanin(pFanin0, 1) );
+ Path[2] = Abc_Var2Lit(pRoot->Id, i);
+ Path[1] = Abc_Var2Lit(pMux->Id, (int)(nMuxes1 == 2) );
+ Path[0] = Abc_Var2Lit(pFanin0->Id, Str_MuxHasFanin(pFanin0, 1));
+ Str_MuxChangeOnce( pTree, Path, 0, 2, NULL, pNew, vDelay );
+ }
+ Str_MuxRestructAreaThree( pNew, Str_MuxFanin(pRoot, i), vDelay, fVerbose );
+ return 0;
+ }
+ assert( nMuxes0 + nMuxes1 == 3 || nMuxes0 + nMuxes1 == 4 );
+ assert( nMuxes0 == 2 || nMuxes1 == 2 );
+ if ( fSkipMoving )
+ {
+ Str_MuxRestructAreaThree( pNew, pMux, vDelay, fVerbose );
+ return 0;
+ }
+ if ( nMuxes0 == 2 )
+ {
+ pFanin0 = Str_MuxFanin( pMux, 0 );
+ assert( Str_MuxHasFanin(pFanin0, 0) != Str_MuxHasFanin(pFanin0, 1) );
+ Path[3] = Abc_Var2Lit(pRoot->Id, i);
+ Path[2] = Abc_Var2Lit(pMux->Id, 0 );
+ Path[1] = Abc_Var2Lit(pFanin0->Id, Str_MuxHasFanin(pFanin0, 1));
+ pFanin1 = Str_MuxFanin( pFanin0, Str_MuxHasFanin(pFanin0, 1) );
+ assert( !Str_MuxHasFanin(pFanin1, 0) && !Str_MuxHasFanin(pFanin1, 1) );
+ Path[0] = Abc_Var2Lit(pFanin1->Id, 0);
+ Str_MuxChangeOnce( pTree, Path, 0, 3, NULL, pNew, vDelay );
+ }
+ if ( nMuxes1 == 2 )
+ {
+ pFanin0 = Str_MuxFanin( pMux, 1 );
+ assert( Str_MuxHasFanin(pFanin0, 0) != Str_MuxHasFanin(pFanin0, 1) );
+ Path[3] = Abc_Var2Lit(pRoot->Id, i);
+ Path[2] = Abc_Var2Lit(pMux->Id, 1 );
+ Path[1] = Abc_Var2Lit(pFanin0->Id, Str_MuxHasFanin(pFanin0, 1));
+ pFanin1 = Str_MuxFanin( pFanin0, Str_MuxHasFanin(pFanin0, 1) );
+ assert( !Str_MuxHasFanin(pFanin1, 0) && !Str_MuxHasFanin(pFanin1, 1) );
+ Path[0] = Abc_Var2Lit(pFanin1->Id, 0);
+ Str_MuxChangeOnce( pTree, Path, 0, 3, NULL, pNew, vDelay );
+ }
+ Str_MuxRestructAreaThree( pNew, pMux, vDelay, fVerbose );
+ return nMuxes0 + nMuxes1 - 2;
+}
+int Str_MuxRestructureArea( Gia_Man_t * pNew, Str_Ntk_t * pNtk, int iMux, int nMuxes, Vec_Int_t * vDelay, int nLutSize, int fVerbose )
+{
+ int Limit = 500;
+ Str_Mux_t pTree[500];
+ int Result;
+ if ( nMuxes >= Limit )
+ return -1;
+ assert( nMuxes < Limit );
+ Str_MuxCreate( pTree, pNtk, iMux, nMuxes, vDelay, nLutSize );
+ Result = Str_MuxRestructArea_rec( pNew, pTree, pTree, 0, vDelay, fVerbose );
+ assert( Result >= 0 && Result <= 2 );
+ return Str_MuxToGia_rec( pNew, pTree, 0, vDelay );
+}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///