blob: 483234ddafdc72ef5e48a4742db986f91906da99 [file] [log] [blame]
/**CFile****************************************************************
FileName [abcReconv.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Network and node package.]
Synopsis [Computation of reconvergence-driven cuts.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: abcReconv.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "base/abc/abc.h"
#ifdef ABC_USE_CUDD
#include "bdd/extrab/extraBdd.h"
#endif
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
struct Abc_ManCut_t_
{
// user specified parameters
int nNodeSizeMax; // the limit on the size of the supernode
int nConeSizeMax; // the limit on the size of the containing cone
int nNodeFanStop; // the limit on the size of the supernode
int nConeFanStop; // the limit on the size of the containing cone
// internal parameters
Vec_Ptr_t * vNodeLeaves; // fanins of the collapsed node (the cut)
Vec_Ptr_t * vConeLeaves; // fanins of the containing cone
Vec_Ptr_t * vVisited; // the visited nodes
Vec_Vec_t * vLevels; // the data structure to compute TFO nodes
Vec_Ptr_t * vNodesTfo; // the nodes in the TFO of the cut
};
static int Abc_NodeBuildCutLevelOne_int( Vec_Ptr_t * vVisited, Vec_Ptr_t * vLeaves, int nSizeLimit, int nFaninLimit );
static int Abc_NodeBuildCutLevelTwo_int( Vec_Ptr_t * vVisited, Vec_Ptr_t * vLeaves, int nFaninLimit );
static void Abc_NodeConeMarkCollect_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vVisited );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Unmarks the TFI cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Abc_NodesMark( Vec_Ptr_t * vVisited )
{
Abc_Obj_t * pNode;
int i;
Vec_PtrForEachEntry( Abc_Obj_t *, vVisited, pNode, i )
pNode->fMarkA = 1;
}
/**Function*************************************************************
Synopsis [Unmarks the TFI cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Abc_NodesUnmark( Vec_Ptr_t * vVisited )
{
Abc_Obj_t * pNode;
int i;
Vec_PtrForEachEntry( Abc_Obj_t *, vVisited, pNode, i )
pNode->fMarkA = 0;
}
/**Function*************************************************************
Synopsis [Unmarks the TFI cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Abc_NodesUnmarkB( Vec_Ptr_t * vVisited )
{
Abc_Obj_t * pNode;
int i;
Vec_PtrForEachEntry( Abc_Obj_t *, vVisited, pNode, i )
pNode->fMarkB = 0;
}
/**Function*************************************************************
Synopsis [Evaluate the cost of removing the node from the set of leaves.]
Description [Returns the number of new leaves that will be brought in.
Returns large number if the node cannot be removed from the set of leaves.]
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Abc_NodeGetLeafCostOne( Abc_Obj_t * pNode, int nFaninLimit )
{
int Cost;
// make sure the node is in the construction zone
assert( pNode->fMarkB == 1 );
// cannot expand over the PI node
if ( Abc_ObjIsCi(pNode) )
return 999;
// get the cost of the cone
Cost = (!Abc_ObjFanin0(pNode)->fMarkB) + (!Abc_ObjFanin1(pNode)->fMarkB);
// always accept if the number of leaves does not increase
if ( Cost < 2 )
return Cost;
// skip nodes with many fanouts
if ( Abc_ObjFanoutNum(pNode) > nFaninLimit )
return 999;
// return the number of nodes that will be on the leaves if this node is removed
return Cost;
}
/**Function*************************************************************
Synopsis [Evaluate the cost of removing the node from the set of leaves.]
Description [Returns the number of new leaves that will be brought in.
Returns large number if the node cannot be removed from the set of leaves.]
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Abc_NodeGetLeafCostTwo( Abc_Obj_t * pNode, int nFaninLimit,
Abc_Obj_t ** ppLeafToAdd, Abc_Obj_t ** pNodeToMark1, Abc_Obj_t ** pNodeToMark2 )
{
Abc_Obj_t * pFanin0, * pFanin1, * pTemp;
Abc_Obj_t * pGrand, * pGrandToAdd;
// make sure the node is in the construction zone
assert( pNode->fMarkB == 1 );
// cannot expand over the PI node
if ( Abc_ObjIsCi(pNode) )
return 999;
// skip nodes with many fanouts
// if ( Abc_ObjFanoutNum(pNode) > nFaninLimit )
// return 999;
// get the children
pFanin0 = Abc_ObjFanin0(pNode);
pFanin1 = Abc_ObjFanin1(pNode);
assert( !pFanin0->fMarkB && !pFanin1->fMarkB );
// count the number of unique grandchildren that will be included
// return infinite cost if this number if more than 1
if ( Abc_ObjIsCi(pFanin0) && Abc_ObjIsCi(pFanin1) )
return 999;
// consider the special case when a non-CI fanin can be dropped
if ( !Abc_ObjIsCi(pFanin0) && Abc_ObjFanin0(pFanin0)->fMarkB && Abc_ObjFanin1(pFanin0)->fMarkB )
{
*ppLeafToAdd = pFanin1;
*pNodeToMark1 = pFanin0;
*pNodeToMark2 = NULL;
return 1;
}
if ( !Abc_ObjIsCi(pFanin1) && Abc_ObjFanin0(pFanin1)->fMarkB && Abc_ObjFanin1(pFanin1)->fMarkB )
{
*ppLeafToAdd = pFanin0;
*pNodeToMark1 = pFanin1;
*pNodeToMark2 = NULL;
return 1;
}
// make the first node CI if any
if ( Abc_ObjIsCi(pFanin1) )
pTemp = pFanin0, pFanin0 = pFanin1, pFanin1 = pTemp;
// consider the first node
pGrandToAdd = NULL;
if ( Abc_ObjIsCi(pFanin0) )
{
*pNodeToMark1 = NULL;
pGrandToAdd = pFanin0;
}
else
{
*pNodeToMark1 = pFanin0;
pGrand = Abc_ObjFanin0(pFanin0);
if ( !pGrand->fMarkB )
{
if ( pGrandToAdd && pGrandToAdd != pGrand )
return 999;
pGrandToAdd = pGrand;
}
pGrand = Abc_ObjFanin1(pFanin0);
if ( !pGrand->fMarkB )
{
if ( pGrandToAdd && pGrandToAdd != pGrand )
return 999;
pGrandToAdd = pGrand;
}
}
// consider the second node
*pNodeToMark2 = pFanin1;
pGrand = Abc_ObjFanin0(pFanin1);
if ( !pGrand->fMarkB )
{
if ( pGrandToAdd && pGrandToAdd != pGrand )
return 999;
pGrandToAdd = pGrand;
}
pGrand = Abc_ObjFanin1(pFanin1);
if ( !pGrand->fMarkB )
{
if ( pGrandToAdd && pGrandToAdd != pGrand )
return 999;
pGrandToAdd = pGrand;
}
assert( pGrandToAdd != NULL );
*ppLeafToAdd = pGrandToAdd;
return 1;
}
/**Function*************************************************************
Synopsis [Finds a fanin-limited, reconvergence-driven cut for the node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NodeFindCut( Abc_ManCut_t * p, Abc_Obj_t * pRoot, int fContain )
{
Abc_Obj_t * pNode;
int i;
assert( !Abc_ObjIsComplement(pRoot) );
assert( Abc_ObjIsNode(pRoot) );
// start the visited nodes and mark them
Vec_PtrClear( p->vVisited );
Vec_PtrPush( p->vVisited, pRoot );
Vec_PtrPush( p->vVisited, Abc_ObjFanin0(pRoot) );
Vec_PtrPush( p->vVisited, Abc_ObjFanin1(pRoot) );
pRoot->fMarkB = 1;
Abc_ObjFanin0(pRoot)->fMarkB = 1;
Abc_ObjFanin1(pRoot)->fMarkB = 1;
// start the cut
Vec_PtrClear( p->vNodeLeaves );
Vec_PtrPush( p->vNodeLeaves, Abc_ObjFanin0(pRoot) );
Vec_PtrPush( p->vNodeLeaves, Abc_ObjFanin1(pRoot) );
// compute the cut
while ( Abc_NodeBuildCutLevelOne_int( p->vVisited, p->vNodeLeaves, p->nNodeSizeMax, p->nNodeFanStop ) );
assert( Vec_PtrSize(p->vNodeLeaves) <= p->nNodeSizeMax );
// return if containing cut is not requested
if ( !fContain )
{
// unmark both fMarkA and fMarkB in tbe TFI
Abc_NodesUnmarkB( p->vVisited );
return p->vNodeLeaves;
}
//printf( "\n\n\n" );
// compute the containing cut
assert( p->nNodeSizeMax < p->nConeSizeMax );
// copy the current boundary
Vec_PtrClear( p->vConeLeaves );
Vec_PtrForEachEntry( Abc_Obj_t *, p->vNodeLeaves, pNode, i )
Vec_PtrPush( p->vConeLeaves, pNode );
// compute the containing cut
while ( Abc_NodeBuildCutLevelOne_int( p->vVisited, p->vConeLeaves, p->nConeSizeMax, p->nConeFanStop ) );
assert( Vec_PtrSize(p->vConeLeaves) <= p->nConeSizeMax );
// unmark TFI using fMarkA and fMarkB
Abc_NodesUnmarkB( p->vVisited );
return p->vNodeLeaves;
}
/**Function*************************************************************
Synopsis [Builds reconvergence-driven cut by changing one leaf at a time.]
Description [This procedure looks at the current leaves and tries to change
one leaf at a time in such a way that the cut grows as little as possible.
In evaluating the fanins, this procedure looks only at their immediate
predecessors (this is why it is called a one-level construction procedure).]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NodeBuildCutLevelOne_int( Vec_Ptr_t * vVisited, Vec_Ptr_t * vLeaves, int nSizeLimit, int nFaninLimit )
{
Abc_Obj_t * pNode, * pFaninBest, * pNext;
int CostBest, CostCur, i;
// find the best fanin
CostBest = 100;
pFaninBest = NULL;
//printf( "Evaluating fanins of the cut:\n" );
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pNode, i )
{
CostCur = Abc_NodeGetLeafCostOne( pNode, nFaninLimit );
//printf( " Fanin %s has cost %d.\n", Abc_ObjName(pNode), CostCur );
// if ( CostBest > CostCur ) // performance improvement: expand the variable with the smallest level
if ( CostBest > CostCur ||
(CostBest == CostCur && pNode->Level > pFaninBest->Level) )
{
CostBest = CostCur;
pFaninBest = pNode;
}
if ( CostBest == 0 )
break;
}
if ( pFaninBest == NULL )
return 0;
// return Abc_NodeBuildCutLevelTwo_int( vVisited, vLeaves, nFaninLimit );
assert( CostBest < 3 );
if ( vLeaves->nSize - 1 + CostBest > nSizeLimit )
return 0;
// return Abc_NodeBuildCutLevelTwo_int( vVisited, vLeaves, nFaninLimit );
assert( Abc_ObjIsNode(pFaninBest) );
// remove the node from the array
Vec_PtrRemove( vLeaves, pFaninBest );
//printf( "Removing fanin %s.\n", Abc_ObjName(pFaninBest) );
// add the left child to the fanins
pNext = Abc_ObjFanin0(pFaninBest);
if ( !pNext->fMarkB )
{
//printf( "Adding fanin %s.\n", Abc_ObjName(pNext) );
pNext->fMarkB = 1;
Vec_PtrPush( vLeaves, pNext );
Vec_PtrPush( vVisited, pNext );
}
// add the right child to the fanins
pNext = Abc_ObjFanin1(pFaninBest);
if ( !pNext->fMarkB )
{
//printf( "Adding fanin %s.\n", Abc_ObjName(pNext) );
pNext->fMarkB = 1;
Vec_PtrPush( vLeaves, pNext );
Vec_PtrPush( vVisited, pNext );
}
assert( vLeaves->nSize <= nSizeLimit );
// keep doing this
return 1;
}
/**Function*************************************************************
Synopsis [Builds reconvergence-driven cut by changing one leaf at a time.]
Description [This procedure looks at the current leaves and tries to change
one leaf at a time in such a way that the cut grows as little as possible.
In evaluating the fanins, this procedure looks across two levels of fanins
(this is why it is called a two-level construction procedure).]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NodeBuildCutLevelTwo_int( Vec_Ptr_t * vVisited, Vec_Ptr_t * vLeaves, int nFaninLimit )
{
Abc_Obj_t * pNode = NULL, * pLeafToAdd, * pNodeToMark1, * pNodeToMark2;
int CostCur = 0, i;
// find the best fanin
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pNode, i )
{
CostCur = Abc_NodeGetLeafCostTwo( pNode, nFaninLimit, &pLeafToAdd, &pNodeToMark1, &pNodeToMark2 );
if ( CostCur < 2 )
break;
}
if ( CostCur > 2 )
return 0;
// remove the node from the array
Vec_PtrRemove( vLeaves, pNode );
// add the node to the leaves
if ( pLeafToAdd )
{
assert( !pLeafToAdd->fMarkB );
pLeafToAdd->fMarkB = 1;
Vec_PtrPush( vLeaves, pLeafToAdd );
Vec_PtrPush( vVisited, pLeafToAdd );
}
// mark the other nodes
if ( pNodeToMark1 )
{
assert( !pNodeToMark1->fMarkB );
pNodeToMark1->fMarkB = 1;
Vec_PtrPush( vVisited, pNodeToMark1 );
}
if ( pNodeToMark2 )
{
assert( !pNodeToMark2->fMarkB );
pNodeToMark2->fMarkB = 1;
Vec_PtrPush( vVisited, pNodeToMark2 );
}
// keep doing this
return 1;
}
/**Function*************************************************************
Synopsis [Get the nodes contained in the cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NodeConeCollect( Abc_Obj_t ** ppRoots, int nRoots, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vVisited, int fIncludeFanins )
{
Abc_Obj_t * pTemp;
int i;
// mark the fanins of the cone
Abc_NodesMark( vLeaves );
// collect the nodes in the DFS order
Vec_PtrClear( vVisited );
// add the fanins
if ( fIncludeFanins )
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pTemp, i )
Vec_PtrPush( vVisited, pTemp );
// add other nodes
for ( i = 0; i < nRoots; i++ )
Abc_NodeConeMarkCollect_rec( ppRoots[i], vVisited );
// unmark both sets
Abc_NodesUnmark( vLeaves );
Abc_NodesUnmark( vVisited );
}
/**Function*************************************************************
Synopsis [Marks the TFI cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NodeConeMarkCollect_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vVisited )
{
if ( pNode->fMarkA == 1 )
return;
// visit transitive fanin
if ( Abc_ObjIsNode(pNode) )
{
Abc_NodeConeMarkCollect_rec( Abc_ObjFanin0(pNode), vVisited );
Abc_NodeConeMarkCollect_rec( Abc_ObjFanin1(pNode), vVisited );
}
assert( pNode->fMarkA == 0 );
pNode->fMarkA = 1;
Vec_PtrPush( vVisited, pNode );
}
#ifdef ABC_USE_CUDD
/**Function*************************************************************
Synopsis [Returns BDD representing the logic function of the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * Abc_NodeConeBdd( DdManager * dd, DdNode ** pbVars, Abc_Obj_t * pRoot, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vVisited )
{
Abc_Obj_t * pNode;
DdNode * bFunc0, * bFunc1, * bFunc = NULL;
int i;
// get the nodes in the cut without fanins in the DFS order
Abc_NodeConeCollect( &pRoot, 1, vLeaves, vVisited, 0 );
// set the elementary BDDs
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pNode, i )
pNode->pCopy = (Abc_Obj_t *)pbVars[i];
// compute the BDDs for the collected nodes
Vec_PtrForEachEntry( Abc_Obj_t *, vVisited, pNode, i )
{
assert( !Abc_ObjIsPi(pNode) );
bFunc0 = Cudd_NotCond( Abc_ObjFanin0(pNode)->pCopy, (int)Abc_ObjFaninC0(pNode) );
bFunc1 = Cudd_NotCond( Abc_ObjFanin1(pNode)->pCopy, (int)Abc_ObjFaninC1(pNode) );
bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc );
pNode->pCopy = (Abc_Obj_t *)bFunc;
}
assert(bFunc);
Cudd_Ref( bFunc );
// dereference the intermediate ones
Vec_PtrForEachEntry( Abc_Obj_t *, vVisited, pNode, i )
Cudd_RecursiveDeref( dd, (DdNode *)pNode->pCopy );
Cudd_Deref( bFunc );
return bFunc;
}
/**Function*************************************************************
Synopsis [Returns BDD representing the transition relation of the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * Abc_NodeConeDcs( DdManager * dd, DdNode ** pbVarsX, DdNode ** pbVarsY, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, Vec_Ptr_t * vVisited )
{
DdNode * bFunc0, * bFunc1, * bFunc, * bTrans, * bTemp, * bCube, * bResult;
Abc_Obj_t * pNode;
int i;
// get the nodes in the cut without fanins in the DFS order
Abc_NodeConeCollect( (Abc_Obj_t **)vRoots->pArray, vRoots->nSize, vLeaves, vVisited, 0 );
// set the elementary BDDs
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pNode, i )
pNode->pCopy = (Abc_Obj_t *)pbVarsX[i];
// compute the BDDs for the collected nodes
Vec_PtrForEachEntry( Abc_Obj_t *, vVisited, pNode, i )
{
bFunc0 = Cudd_NotCond( Abc_ObjFanin0(pNode)->pCopy, (int)Abc_ObjFaninC0(pNode) );
bFunc1 = Cudd_NotCond( Abc_ObjFanin1(pNode)->pCopy, (int)Abc_ObjFaninC1(pNode) );
bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc );
pNode->pCopy = (Abc_Obj_t *)bFunc;
}
// compute the transition relation of the cone
bTrans = b1; Cudd_Ref( bTrans );
Vec_PtrForEachEntry( Abc_Obj_t *, vRoots, pNode, i )
{
bFunc = Cudd_bddXnor( dd, (DdNode *)pNode->pCopy, pbVarsY[i] ); Cudd_Ref( bFunc );
bTrans = Cudd_bddAnd( dd, bTemp = bTrans, bFunc ); Cudd_Ref( bTrans );
Cudd_RecursiveDeref( dd, bTemp );
Cudd_RecursiveDeref( dd, bFunc );
}
// dereference the intermediate ones
Vec_PtrForEachEntry( Abc_Obj_t *, vVisited, pNode, i )
Cudd_RecursiveDeref( dd, (DdNode *)pNode->pCopy );
// compute don't-cares
bCube = Extra_bddComputeRangeCube( dd, vRoots->nSize, vRoots->nSize + vLeaves->nSize ); Cudd_Ref( bCube );
bResult = Cudd_bddExistAbstract( dd, bTrans, bCube ); Cudd_Ref( bResult );
bResult = Cudd_Not( bResult );
Cudd_RecursiveDeref( dd, bCube );
Cudd_RecursiveDeref( dd, bTrans );
Cudd_Deref( bResult );
return bResult;
}
#endif
/**Function*************************************************************
Synopsis [Starts the resynthesis manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_ManCut_t * Abc_NtkManCutStart( int nNodeSizeMax, int nConeSizeMax, int nNodeFanStop, int nConeFanStop )
{
Abc_ManCut_t * p;
p = ABC_ALLOC( Abc_ManCut_t, 1 );
memset( p, 0, sizeof(Abc_ManCut_t) );
p->vNodeLeaves = Vec_PtrAlloc( 100 );
p->vConeLeaves = Vec_PtrAlloc( 100 );
p->vVisited = Vec_PtrAlloc( 100 );
p->vLevels = Vec_VecAlloc( 100 );
p->vNodesTfo = Vec_PtrAlloc( 100 );
p->nNodeSizeMax = nNodeSizeMax;
p->nConeSizeMax = nConeSizeMax;
p->nNodeFanStop = nNodeFanStop;
p->nConeFanStop = nConeFanStop;
return p;
}
/**Function*************************************************************
Synopsis [Stops the resynthesis manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkManCutStop( Abc_ManCut_t * p )
{
Vec_PtrFree( p->vNodeLeaves );
Vec_PtrFree( p->vConeLeaves );
Vec_PtrFree( p->vVisited );
Vec_VecFree( p->vLevels );
Vec_PtrFree( p->vNodesTfo );
ABC_FREE( p );
}
/**Function*************************************************************
Synopsis [Returns the leaves of the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkManCutReadCutLarge( Abc_ManCut_t * p )
{
return p->vConeLeaves;
}
/**Function*************************************************************
Synopsis [Returns the leaves of the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkManCutReadCutSmall( Abc_ManCut_t * p )
{
return p->vNodeLeaves;
}
/**Function*************************************************************
Synopsis [Returns the leaves of the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkManCutReadVisited( Abc_ManCut_t * p )
{
return p->vVisited;
}
/**Function*************************************************************
Synopsis [Collects the TFO of the cut in the topological order.]
Description [TFO of the cut is defined as a set of nodes, for which the cut
is a cut, that is, every path from the collected nodes to the CIs goes through
a node in the cut. The nodes are collected if their level does not exceed
the given number (LevelMax). The nodes are returned in the topological order.
If the root node is given, its MFFC is marked, so that the collected nodes
do not contain any nodes in the MFFC.]
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NodeCollectTfoCands( Abc_ManCut_t * p, Abc_Obj_t * pRoot, Vec_Ptr_t * vLeaves, int LevelMax )
{
Abc_Ntk_t * pNtk = pRoot->pNtk;
Vec_Ptr_t * vVec;
Abc_Obj_t * pNode, * pFanout;
int i, k, v, LevelMin;
assert( Abc_NtkIsStrash(pNtk) );
// assuming that the structure is clean
Vec_VecForEachLevel( p->vLevels, vVec, i )
assert( vVec->nSize == 0 );
// put fanins into the structure while labeling them
Abc_NtkIncrementTravId( pNtk );
LevelMin = -1;
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pNode, i )
{
if ( pNode->Level > (unsigned)LevelMax )
continue;
Abc_NodeSetTravIdCurrent( pNode );
Vec_VecPush( p->vLevels, pNode->Level, pNode );
if ( LevelMin < (int)pNode->Level )
LevelMin = pNode->Level;
}
assert( LevelMin >= 0 );
// mark MFFC
if ( pRoot )
Abc_NodeMffcLabelAig( pRoot );
// go through the levels up
Vec_PtrClear( p->vNodesTfo );
Vec_VecForEachEntryStart( Abc_Obj_t *, p->vLevels, pNode, i, k, LevelMin )
{
if ( i > LevelMax )
break;
// if the node is not marked, it is not a fanin
if ( !Abc_NodeIsTravIdCurrent(pNode) )
{
// check if it belongs to the TFO
if ( !Abc_NodeIsTravIdCurrent(Abc_ObjFanin0(pNode)) ||
!Abc_NodeIsTravIdCurrent(Abc_ObjFanin1(pNode)) )
continue;
// save the node in the TFO and label it
Vec_PtrPush( p->vNodesTfo, pNode );
Abc_NodeSetTravIdCurrent( pNode );
}
// go through the fanouts and add them to the structure if they meet the conditions
Abc_ObjForEachFanout( pNode, pFanout, v )
{
// skip if fanout is a CO or its level exceeds
if ( Abc_ObjIsCo(pFanout) || pFanout->Level > (unsigned)LevelMax )
continue;
// skip if it is already added or if it is in MFFC
if ( Abc_NodeIsTravIdCurrent(pFanout) )
continue;
// add it to the structure but do not mark it (until tested later)
Vec_VecPushUnique( p->vLevels, pFanout->Level, pFanout );
}
}
// clear the levelized structure
Vec_VecForEachLevelStart( p->vLevels, vVec, i, LevelMin )
{
if ( i > LevelMax )
break;
Vec_PtrClear( vVec );
}
return p->vNodesTfo;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END