blob: fc654bc92b2f16be5efc101b5d5eb2235deff80d [file] [log] [blame]
/**CFile****************************************************************
FileName [abcPart.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Network and node package.]
Synopsis [Output partitioning package.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: abcPart.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "base/abc/abc.h"
#include "base/main/main.h"
#include "base/cmd/cmd.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
typedef struct Supp_Man_t_ Supp_Man_t;
struct Supp_Man_t_
{
int nChunkSize; // the size of one chunk of memory (~1 MB)
int nStepSize; // the step size in saving memory (~64 bytes)
char * pFreeBuf; // the pointer to free memory
int nFreeSize; // the size of remaining free memory
Vec_Ptr_t * vMemory; // the memory allocated
Vec_Ptr_t * vFree; // the vector of free pieces of memory
};
typedef struct Supp_One_t_ Supp_One_t;
struct Supp_One_t_
{
int nRefs; // the number of references
int nOuts; // the number of outputs
int nOutsAlloc; // the array size
int pOuts[0]; // the array of outputs
};
static inline int Supp_SizeType( int nSize, int nStepSize ) { return nSize / nStepSize + ((nSize % nStepSize) > 0); }
static inline char * Supp_OneNext( char * pPart ) { return *((char **)pPart); }
static inline void Supp_OneSetNext( char * pPart, char * pNext ) { *((char **)pPart) = pNext; }
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Start the memory manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Supp_Man_t * Supp_ManStart( int nChunkSize, int nStepSize )
{
Supp_Man_t * p;
p = ABC_ALLOC( Supp_Man_t, 1 );
memset( p, 0, sizeof(Supp_Man_t) );
p->nChunkSize = nChunkSize;
p->nStepSize = nStepSize;
p->vMemory = Vec_PtrAlloc( 1000 );
p->vFree = Vec_PtrAlloc( 1000 );
return p;
}
/**Function*************************************************************
Synopsis [Stops the memory manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Supp_ManStop( Supp_Man_t * p )
{
void * pMemory;
int i;
Vec_PtrForEachEntry( void *, p->vMemory, pMemory, i )
ABC_FREE( pMemory );
Vec_PtrFree( p->vMemory );
Vec_PtrFree( p->vFree );
ABC_FREE( p );
}
/**Function*************************************************************
Synopsis [Fetches the memory entry of the given size.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
char * Supp_ManFetch( Supp_Man_t * p, int nSize )
{
int Type, nSizeReal;
char * pMemory;
assert( nSize > 0 );
Type = Supp_SizeType( nSize, p->nStepSize );
Vec_PtrFillExtra( p->vFree, Type + 1, NULL );
if ( (pMemory = (char *)Vec_PtrEntry( p->vFree, Type )) )
{
Vec_PtrWriteEntry( p->vFree, Type, Supp_OneNext(pMemory) );
return pMemory;
}
nSizeReal = p->nStepSize * Type;
if ( p->nFreeSize < nSizeReal )
{
p->pFreeBuf = ABC_ALLOC( char, p->nChunkSize );
p->nFreeSize = p->nChunkSize;
Vec_PtrPush( p->vMemory, p->pFreeBuf );
}
assert( p->nFreeSize >= nSizeReal );
pMemory = p->pFreeBuf;
p->pFreeBuf += nSizeReal;
p->nFreeSize -= nSizeReal;
return pMemory;
}
/**Function*************************************************************
Synopsis [Recycles the memory entry of the given size.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Supp_ManRecycle( Supp_Man_t * p, char * pMemory, int nSize )
{
int Type;
Type = Supp_SizeType( nSize, p->nStepSize );
Vec_PtrFillExtra( p->vFree, Type + 1, NULL );
Supp_OneSetNext( pMemory, (char *)Vec_PtrEntry(p->vFree, Type) );
Vec_PtrWriteEntry( p->vFree, Type, pMemory );
}
/**Function*************************************************************
Synopsis [Fetches the memory entry of the given size.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline Supp_One_t * Supp_ManFetchEntry( Supp_Man_t * p, int nWords, int nRefs )
{
Supp_One_t * pPart;
pPart = (Supp_One_t *)Supp_ManFetch( p, sizeof(Supp_One_t) + sizeof(int) * nWords );
pPart->nRefs = nRefs;
pPart->nOuts = 0;
pPart->nOutsAlloc = nWords;
return pPart;
}
/**Function*************************************************************
Synopsis [Recycles the memory entry of the given size.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Supp_ManRecycleEntry( Supp_Man_t * p, Supp_One_t * pEntry )
{
assert( pEntry->nOuts <= pEntry->nOutsAlloc );
assert( pEntry->nOuts >= pEntry->nOutsAlloc/2 );
Supp_ManRecycle( p, (char *)pEntry, sizeof(Supp_One_t) + sizeof(int) * pEntry->nOutsAlloc );
}
/**Function*************************************************************
Synopsis [Merges two entries.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Supp_One_t * Supp_ManMergeEntry( Supp_Man_t * pMan, Supp_One_t * p1, Supp_One_t * p2, int nRefs )
{
Supp_One_t * p = Supp_ManFetchEntry( pMan, p1->nOuts + p2->nOuts, nRefs );
int * pBeg1 = p1->pOuts;
int * pBeg2 = p2->pOuts;
int * pBeg = p->pOuts;
int * pEnd1 = p1->pOuts + p1->nOuts;
int * pEnd2 = p2->pOuts + p2->nOuts;
while ( pBeg1 < pEnd1 && pBeg2 < pEnd2 )
{
if ( *pBeg1 == *pBeg2 )
*pBeg++ = *pBeg1++, pBeg2++;
else if ( *pBeg1 < *pBeg2 )
*pBeg++ = *pBeg1++;
else
*pBeg++ = *pBeg2++;
}
while ( pBeg1 < pEnd1 )
*pBeg++ = *pBeg1++;
while ( pBeg2 < pEnd2 )
*pBeg++ = *pBeg2++;
p->nOuts = pBeg - p->pOuts;
assert( p->nOuts <= p->nOutsAlloc );
assert( p->nOuts >= p1->nOuts );
assert( p->nOuts >= p2->nOuts );
return p;
}
/**Function*************************************************************
Synopsis [Tranfers the entry.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Int_t * Supp_ManTransferEntry( Supp_One_t * p )
{
Vec_Int_t * vSupp;
int i;
vSupp = Vec_IntAlloc( p->nOuts );
for ( i = 0; i < p->nOuts; i++ )
Vec_IntPush( vSupp, p->pOuts[i] );
return vSupp;
}
/**Function*************************************************************
Synopsis [Computes supports of the POs in the multi-output AIG.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkDfsNatural( Abc_Ntk_t * pNtk )
{
Vec_Ptr_t * vNodes;
Abc_Obj_t * pObj, * pNext;
int i, k;
assert( Abc_NtkIsStrash(pNtk) );
vNodes = Vec_PtrAlloc( Abc_NtkObjNum(pNtk) );
Abc_NtkIncrementTravId( pNtk );
// add the constant-1 nodes
pObj = Abc_AigConst1(pNtk);
Abc_NodeSetTravIdCurrent( pObj );
Vec_PtrPush( vNodes, pObj );
// add the CIs/nodes/COs in the topological order
Abc_NtkForEachNode( pNtk, pObj, i )
{
// check the fanins and add CIs
Abc_ObjForEachFanin( pObj, pNext, k )
if ( Abc_ObjIsCi(pNext) && !Abc_NodeIsTravIdCurrent(pNext) )
{
Abc_NodeSetTravIdCurrent( pNext );
Vec_PtrPush( vNodes, pNext );
}
// add the node
Vec_PtrPush( vNodes, pObj );
// check the fanouts and add COs
Abc_ObjForEachFanout( pObj, pNext, k )
if ( Abc_ObjIsCo(pNext) && !Abc_NodeIsTravIdCurrent(pNext) )
{
Abc_NodeSetTravIdCurrent( pNext );
Vec_PtrPush( vNodes, pNext );
}
}
return vNodes;
}
/**Function*************************************************************
Synopsis [Computes supports of the POs.]
Description [Returns the ptr-vector of int-vectors.]
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkComputeSupportsSmart( Abc_Ntk_t * pNtk )
{
Vec_Ptr_t * vSupports;
Vec_Ptr_t * vNodes;
Vec_Int_t * vSupp;
Supp_Man_t * p;
Supp_One_t * pPart0, * pPart1;
Abc_Obj_t * pObj;
int i;
// set the number of PIs/POs
Abc_NtkForEachCi( pNtk, pObj, i )
pObj->pNext = (Abc_Obj_t *)(ABC_PTRINT_T)i;
Abc_NtkForEachCo( pNtk, pObj, i )
pObj->pNext = (Abc_Obj_t *)(ABC_PTRINT_T)i;
// start the support computation manager
p = Supp_ManStart( 1 << 20, 1 << 6 );
// consider objects in the topological order
vSupports = Vec_PtrAlloc( Abc_NtkCoNum(pNtk) );
Abc_NtkCleanCopy(pNtk);
// order the nodes so that the PIs and POs follow naturally
vNodes = Abc_NtkDfsNatural( pNtk );
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
{
if ( Abc_ObjIsNode(pObj) )
{
pPart0 = (Supp_One_t *)Abc_ObjFanin0(pObj)->pCopy;
pPart1 = (Supp_One_t *)Abc_ObjFanin1(pObj)->pCopy;
pObj->pCopy = (Abc_Obj_t *)Supp_ManMergeEntry( p, pPart0, pPart1, Abc_ObjFanoutNum(pObj) );
assert( pPart0->nRefs > 0 );
if ( --pPart0->nRefs == 0 )
Supp_ManRecycleEntry( p, pPart0 );
assert( pPart1->nRefs > 0 );
if ( --pPart1->nRefs == 0 )
Supp_ManRecycleEntry( p, pPart1 );
continue;
}
if ( Abc_ObjIsCo(pObj) )
{
pPart0 = (Supp_One_t *)Abc_ObjFanin0(pObj)->pCopy;
// only save the CO if it is non-trivial
if ( Abc_ObjIsNode(Abc_ObjFanin0(pObj)) )
{
vSupp = Supp_ManTransferEntry(pPart0);
Vec_IntPush( vSupp, (int)(ABC_PTRINT_T)pObj->pNext );
Vec_PtrPush( vSupports, vSupp );
}
assert( pPart0->nRefs > 0 );
if ( --pPart0->nRefs == 0 )
Supp_ManRecycleEntry( p, pPart0 );
continue;
}
if ( Abc_ObjIsCi(pObj) )
{
if ( Abc_ObjFanoutNum(pObj) )
{
pPart0 = (Supp_One_t *)Supp_ManFetchEntry( p, 1, Abc_ObjFanoutNum(pObj) );
pPart0->pOuts[ pPart0->nOuts++ ] = (int)(ABC_PTRINT_T)pObj->pNext;
pObj->pCopy = (Abc_Obj_t *)pPart0;
}
continue;
}
if ( pObj == Abc_AigConst1(pNtk) )
{
if ( Abc_ObjFanoutNum(pObj) )
pObj->pCopy = (Abc_Obj_t *)Supp_ManFetchEntry( p, 0, Abc_ObjFanoutNum(pObj) );
continue;
}
assert( 0 );
}
Vec_PtrFree( vNodes );
//printf( "Memory usage = %d MB.\n", Vec_PtrSize(p->vMemory) * p->nChunkSize / (1<<20) );
Supp_ManStop( p );
// sort supports by size
Vec_VecSort( (Vec_Vec_t *)vSupports, 1 );
// clear the number of PIs/POs
Abc_NtkForEachCi( pNtk, pObj, i )
pObj->pNext = NULL;
Abc_NtkForEachCo( pNtk, pObj, i )
pObj->pNext = NULL;
/*
Vec_PtrForEachEntry( Vec_Int_t *, vSupports, vSupp, i )
printf( "%d ", Vec_IntSize(vSupp) );
printf( "\n" );
*/
return vSupports;
}
/**Function*************************************************************
Synopsis [Computes supports of the POs using naive method.]
Description [Returns the ptr-vector of int-vectors.]
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkComputeSupportsNaive( Abc_Ntk_t * pNtk )
{
Vec_Ptr_t * vSupp, * vSupports;
Vec_Int_t * vSuppI;
Abc_Obj_t * pObj, * pTemp;
int i, k;
// set the PI numbers
Abc_NtkForEachCi( pNtk, pObj, i )
pObj->pNext = (Abc_Obj_t *)(ABC_PTRINT_T)i;
// save the CI numbers
vSupports = Vec_PtrAlloc( Abc_NtkCoNum(pNtk) );
Abc_NtkForEachCo( pNtk, pObj, i )
{
if ( !Abc_ObjIsNode(Abc_ObjFanin0(pObj)) )
continue;
vSupp = Abc_NtkNodeSupport( pNtk, &pObj, 1 );
vSuppI = (Vec_Int_t *)vSupp;
Vec_PtrForEachEntry( Abc_Obj_t *, vSupp, pTemp, k )
Vec_IntWriteEntry( vSuppI, k, (int)(ABC_PTRINT_T)pTemp->pNext );
Vec_IntSort( vSuppI, 0 );
// append the number of this output
Vec_IntPush( vSuppI, i );
// save the support in the vector
Vec_PtrPush( vSupports, vSuppI );
}
// clean the CI numbers
Abc_NtkForEachCi( pNtk, pObj, i )
pObj->pNext = NULL;
// sort supports by size
Vec_VecSort( (Vec_Vec_t *)vSupports, 1 );
/*
Vec_PtrForEachEntry( Vec_Int_t *, vSupports, vSuppI, i )
printf( "%d ", Vec_IntSize(vSuppI) );
printf( "\n" );
*/
return vSupports;
}
/**Function*************************************************************
Synopsis [Start bitwise support representation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
unsigned * Abc_NtkSuppCharStart( Vec_Int_t * vOne, int nPis )
{
unsigned * pBuffer;
int i, Entry;
int nWords = Abc_BitWordNum(nPis);
pBuffer = ABC_ALLOC( unsigned, nWords );
memset( pBuffer, 0, sizeof(unsigned) * nWords );
Vec_IntForEachEntry( vOne, Entry, i )
{
assert( Entry < nPis );
Abc_InfoSetBit( pBuffer, Entry );
}
return pBuffer;
}
/**Function*************************************************************
Synopsis [Add to bitwise support representation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkSuppCharAdd( unsigned * pBuffer, Vec_Int_t * vOne, int nPis )
{
int i, Entry;
Vec_IntForEachEntry( vOne, Entry, i )
{
assert( Entry < nPis );
Abc_InfoSetBit( pBuffer, Entry );
}
}
/**Function*************************************************************
Synopsis [Find the common variables using bitwise support representation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkSuppCharCommon( unsigned * pBuffer, Vec_Int_t * vOne )
{
int i, Entry, nCommon = 0;
Vec_IntForEachEntry( vOne, Entry, i )
nCommon += Abc_InfoHasBit(pBuffer, Entry);
return nCommon;
}
/**Function*************************************************************
Synopsis [Find the best partition.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkPartitionSmartFindPart( Vec_Ptr_t * vPartSuppsAll, Vec_Ptr_t * vPartsAll, Vec_Ptr_t * vPartSuppsChar, int nSuppSizeLimit, Vec_Int_t * vOne )
{
/*
Vec_Int_t * vPartSupp, * vPart;
double Attract, Repulse, Cost, CostBest;
int i, nCommon, iBest;
iBest = -1;
CostBest = 0.0;
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vPartSupp, i )
{
vPart = Vec_PtrEntry( vPartsAll, i );
if ( nPartSizeLimit > 0 && Vec_IntSize(vPart) >= nPartSizeLimit )
continue;
nCommon = Vec_IntTwoCountCommon( vPartSupp, vOne );
if ( nCommon == 0 )
continue;
if ( nCommon == Vec_IntSize(vOne) )
return i;
Attract = 1.0 * nCommon / Vec_IntSize(vOne);
if ( Vec_IntSize(vPartSupp) < 100 )
Repulse = 1.0;
else
Repulse = log10( Vec_IntSize(vPartSupp) / 10.0 );
Cost = pow( Attract, pow(Repulse, 5.0) );
if ( CostBest < Cost )
{
CostBest = Cost;
iBest = i;
}
}
if ( CostBest < 0.6 )
return -1;
return iBest;
*/
Vec_Int_t * vPartSupp;//, * vPart;
int Attract, Repulse, Value, ValueBest;
int i, nCommon, iBest;
// int nCommon2;
iBest = -1;
ValueBest = 0;
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vPartSupp, i )
{
// skip partitions with too many outputs
// vPart = Vec_PtrEntry( vPartsAll, i );
// if ( nSuppSizeLimit > 0 && Vec_IntSize(vPart) >= nSuppSizeLimit )
// continue;
// find the number of common variables between this output and the partitions
// nCommon2 = Vec_IntTwoCountCommon( vPartSupp, vOne );
nCommon = Abc_NtkSuppCharCommon( (unsigned *)Vec_PtrEntry(vPartSuppsChar, i), vOne );
// assert( nCommon2 == nCommon );
// if no common variables, continue searching
if ( nCommon == 0 )
continue;
// if all variables are common, the best partition if found
if ( nCommon == Vec_IntSize(vOne) )
return i;
// skip partitions whose size exceeds the limit
if ( nSuppSizeLimit > 0 && Vec_IntSize(vPartSupp) >= 2 * nSuppSizeLimit )
continue;
// figure out might be the good partition for this one
Attract = 1000 * nCommon / Vec_IntSize(vOne);
if ( Vec_IntSize(vPartSupp) < 100 )
Repulse = 1;
else
Repulse = 1+Abc_Base2Log(Vec_IntSize(vPartSupp)-100);
Value = Attract/Repulse;
if ( ValueBest < Value )
{
ValueBest = Value;
iBest = i;
}
}
if ( ValueBest < 75 )
return -1;
return iBest;
}
/**Function*************************************************************
Synopsis [Perform the smart partitioning.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkPartitionPrint( Abc_Ntk_t * pNtk, Vec_Ptr_t * vPartsAll, Vec_Ptr_t * vPartSuppsAll )
{
Vec_Int_t * vOne;
int i, nOutputs, Counter;
Counter = 0;
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
{
nOutputs = Vec_IntSize((Vec_Int_t *)Vec_PtrEntry(vPartsAll, i));
printf( "%d=(%d,%d) ", i, Vec_IntSize(vOne), nOutputs );
Counter += nOutputs;
if ( i == Vec_PtrSize(vPartsAll) - 1 )
break;
}
// assert( Counter == Abc_NtkCoNum(pNtk) );
printf( "\nTotal = %d. Outputs = %d.\n", Counter, Abc_NtkCoNum(pNtk) );
}
/**Function*************************************************************
Synopsis [Perform the smart partitioning.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkPartitionCompact( Vec_Ptr_t * vPartsAll, Vec_Ptr_t * vPartSuppsAll, int nSuppSizeLimit )
{
Vec_Int_t * vOne, * vPart, * vPartSupp, * vTemp;
int i, iPart;
if ( nSuppSizeLimit == 0 )
nSuppSizeLimit = 200;
// pack smaller partitions into larger blocks
iPart = 0;
vPart = vPartSupp = NULL;
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
{
if ( Vec_IntSize(vOne) < nSuppSizeLimit )
{
if ( vPartSupp == NULL )
{
assert( vPart == NULL );
vPartSupp = Vec_IntDup(vOne);
vPart = (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i);
}
else
{
vPartSupp = Vec_IntTwoMerge( vTemp = vPartSupp, vOne );
Vec_IntFree( vTemp );
vPart = Vec_IntTwoMerge( vTemp = vPart, (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i) );
Vec_IntFree( vTemp );
Vec_IntFree( (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i) );
}
if ( Vec_IntSize(vPartSupp) < nSuppSizeLimit )
continue;
}
else
vPart = (Vec_Int_t *)Vec_PtrEntry(vPartsAll, i);
// add the partition
Vec_PtrWriteEntry( vPartsAll, iPart, vPart );
vPart = NULL;
if ( vPartSupp )
{
Vec_IntFree( (Vec_Int_t *)Vec_PtrEntry(vPartSuppsAll, iPart) );
Vec_PtrWriteEntry( vPartSuppsAll, iPart, vPartSupp );
vPartSupp = NULL;
}
iPart++;
}
// add the last one
if ( vPart )
{
Vec_PtrWriteEntry( vPartsAll, iPart, vPart );
vPart = NULL;
assert( vPartSupp != NULL );
Vec_IntFree( (Vec_Int_t *)Vec_PtrEntry(vPartSuppsAll, iPart) );
Vec_PtrWriteEntry( vPartSuppsAll, iPart, vPartSupp );
vPartSupp = NULL;
iPart++;
}
Vec_PtrShrink( vPartsAll, iPart );
Vec_PtrShrink( vPartsAll, iPart );
}
/**Function*************************************************************
Synopsis [Perform the smart partitioning.]
Description [Returns the ptr-vector of int-vectors.]
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkPartitionSmart( Abc_Ntk_t * pNtk, int nSuppSizeLimit, int fVerbose )
{
ProgressBar * pProgress;
Vec_Ptr_t * vPartSuppsChar;
Vec_Ptr_t * vSupps, * vPartsAll, * vPartsAll2, * vPartSuppsAll;
Vec_Int_t * vOne, * vPart, * vPartSupp, * vTemp;
int i, iPart, iOut, timeFind = 0;
abctime clk, clk2;
// compute the supports for all outputs
clk = Abc_Clock();
// vSupps = Abc_NtkComputeSupportsNaive( pNtk );
vSupps = Abc_NtkComputeSupportsSmart( pNtk );
if ( fVerbose )
{
ABC_PRT( "Supps", Abc_Clock() - clk );
}
// start char-based support representation
vPartSuppsChar = Vec_PtrAlloc( 1000 );
// create partitions
clk = Abc_Clock();
vPartsAll = Vec_PtrAlloc( 256 );
vPartSuppsAll = Vec_PtrAlloc( 256 );
pProgress = Extra_ProgressBarStart( stdout, Vec_PtrSize(vSupps) );
Vec_PtrForEachEntry( Vec_Int_t *, vSupps, vOne, i )
{
Extra_ProgressBarUpdate( pProgress, i, NULL );
// if ( i % 1000 == 0 )
// printf( "CIs = %6d. COs = %6d. Processed = %6d (out of %6d). Parts = %6d.\r",
// Abc_NtkCiNum(pNtk), Abc_NtkCoNum(pNtk), i, Vec_PtrSize(vSupps), Vec_PtrSize(vPartsAll) );
// get the output number
iOut = Vec_IntPop(vOne);
// find closely matching part
clk2 = Abc_Clock();
iPart = Abc_NtkPartitionSmartFindPart( vPartSuppsAll, vPartsAll, vPartSuppsChar, nSuppSizeLimit, vOne );
timeFind += Abc_Clock() - clk2;
if ( iPart == -1 )
{
// create new partition
vPart = Vec_IntAlloc( 32 );
Vec_IntPush( vPart, iOut );
// create new partition support
vPartSupp = Vec_IntDup( vOne );
// add this partition and its support
Vec_PtrPush( vPartsAll, vPart );
Vec_PtrPush( vPartSuppsAll, vPartSupp );
Vec_PtrPush( vPartSuppsChar, Abc_NtkSuppCharStart(vOne, Abc_NtkCiNum(pNtk)) );
}
else
{
// add output to this partition
vPart = (Vec_Int_t *)Vec_PtrEntry( vPartsAll, iPart );
Vec_IntPush( vPart, iOut );
// merge supports
vPartSupp = (Vec_Int_t *)Vec_PtrEntry( vPartSuppsAll, iPart );
vPartSupp = Vec_IntTwoMerge( vTemp = vPartSupp, vOne );
Vec_IntFree( vTemp );
// reinsert new support
Vec_PtrWriteEntry( vPartSuppsAll, iPart, vPartSupp );
Abc_NtkSuppCharAdd( (unsigned *)Vec_PtrEntry(vPartSuppsChar, iPart), vOne, Abc_NtkCiNum(pNtk) );
}
}
Extra_ProgressBarStop( pProgress );
// stop char-based support representation
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsChar, vTemp, i )
ABC_FREE( vTemp );
Vec_PtrFree( vPartSuppsChar );
//printf( "\n" );
if ( fVerbose )
{
ABC_PRT( "Parts", Abc_Clock() - clk );
//ABC_PRT( "Find ", timeFind );
}
clk = Abc_Clock();
// remember number of supports
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
Vec_IntPush( vOne, i );
// sort the supports in the decreasing order
Vec_VecSort( (Vec_Vec_t *)vPartSuppsAll, 1 );
// reproduce partitions
vPartsAll2 = Vec_PtrAlloc( 256 );
Vec_PtrForEachEntry( Vec_Int_t *, vPartSuppsAll, vOne, i )
Vec_PtrPush( vPartsAll2, Vec_PtrEntry(vPartsAll, Vec_IntPop(vOne)) );
Vec_PtrFree( vPartsAll );
vPartsAll = vPartsAll2;
// compact small partitions
// Abc_NtkPartitionPrint( pNtk, vPartsAll, vPartSuppsAll );
Abc_NtkPartitionCompact( vPartsAll, vPartSuppsAll, nSuppSizeLimit );
if ( fVerbose )
{
ABC_PRT( "Comps", Abc_Clock() - clk );
}
if ( fVerbose )
printf( "Created %d partitions.\n", Vec_PtrSize(vPartsAll) );
// Abc_NtkPartitionPrint( pNtk, vPartsAll, vPartSuppsAll );
// cleanup
Vec_VecFree( (Vec_Vec_t *)vSupps );
Vec_VecFree( (Vec_Vec_t *)vPartSuppsAll );
/*
// converts from intergers to nodes
Vec_PtrForEachEntry( Vec_Int_t *, vPartsAll, vPart, iPart )
{
vPartPtr = Vec_PtrAlloc( Vec_IntSize(vPart) );
Vec_IntForEachEntry( vPart, iOut, i )
Vec_PtrPush( vPartPtr, Abc_NtkCo(pNtk, iOut) );
Vec_IntFree( vPart );
Vec_PtrWriteEntry( vPartsAll, iPart, vPartPtr );
}
*/
return vPartsAll;
}
/**Function*************************************************************
Synopsis [Perform the naive partitioning.]
Description [Returns the ptr-vector of int-vectors.]
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkPartitionNaive( Abc_Ntk_t * pNtk, int nPartSize )
{
Vec_Ptr_t * vParts;
Abc_Obj_t * pObj;
int nParts, i;
nParts = (Abc_NtkCoNum(pNtk) / nPartSize) + ((Abc_NtkCoNum(pNtk) % nPartSize) > 0);
vParts = (Vec_Ptr_t *)Vec_VecStart( nParts );
Abc_NtkForEachCo( pNtk, pObj, i )
Vec_IntPush( (Vec_Int_t *)Vec_PtrEntry(vParts, i / nPartSize), i );
return vParts;
}
/**Function*************************************************************
Synopsis [Converts from intergers to pointers for the given network.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkConvertCos( Abc_Ntk_t * pNtk, Vec_Int_t * vOuts, Vec_Ptr_t * vOutsPtr )
{
int Out, i;
Vec_PtrClear( vOutsPtr );
Vec_IntForEachEntry( vOuts, Out, i )
Vec_PtrPush( vOutsPtr, Abc_NtkCo(pNtk, Out) );
}
/**Function*************************************************************
Synopsis [Returns representative of the given node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Obj_t * Abc_NtkPartStitchFindRepr_rec( Vec_Ptr_t * vEquiv, Abc_Obj_t * pObj )
{
Abc_Obj_t * pRepr;
pRepr = (Abc_Obj_t *)Vec_PtrEntry( vEquiv, pObj->Id );
if ( pRepr == NULL || pRepr == pObj )
return pObj;
return Abc_NtkPartStitchFindRepr_rec( vEquiv, pRepr );
}
/**Function*************************************************************
Synopsis [Returns the representative of the fanin.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline Abc_Obj_t * Abc_NtkPartStitchCopy0( Vec_Ptr_t * vEquiv, Abc_Obj_t * pObj )
{
Abc_Obj_t * pFan = Abc_ObjFanin0( pObj );
Abc_Obj_t * pRepr = Abc_NtkPartStitchFindRepr_rec( vEquiv, pFan );
return Abc_ObjNotCond( pRepr->pCopy, pRepr->fPhase ^ pFan->fPhase ^ (int)Abc_ObjFaninC1(pObj) );
}
static inline Abc_Obj_t * Abc_NtkPartStitchCopy1( Vec_Ptr_t * vEquiv, Abc_Obj_t * pObj )
{
Abc_Obj_t * pFan = Abc_ObjFanin1( pObj );
Abc_Obj_t * pRepr = Abc_NtkPartStitchFindRepr_rec( vEquiv, pFan );
return Abc_ObjNotCond( pRepr->pCopy, pRepr->fPhase ^ pFan->fPhase ^ (int)Abc_ObjFaninC1(pObj) );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline Hop_Obj_t * Hop_ObjChild0Next( Abc_Obj_t * pObj ) { return Hop_NotCond( (Hop_Obj_t *)Abc_ObjFanin0(pObj)->pNext, Abc_ObjFaninC0(pObj) ); }
static inline Hop_Obj_t * Hop_ObjChild1Next( Abc_Obj_t * pObj ) { return Hop_NotCond( (Hop_Obj_t *)Abc_ObjFanin1(pObj)->pNext, Abc_ObjFaninC1(pObj) ); }
/**Function*************************************************************
Synopsis [Stitches together several networks with choice nodes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Hop_Man_t * Abc_NtkPartStartHop( Abc_Ntk_t * pNtk )
{
Hop_Man_t * pMan;
Abc_Obj_t * pObj;
int i;
// start the HOP package
pMan = Hop_ManStart();
pMan->vObjs = Vec_PtrAlloc( Abc_NtkObjNumMax(pNtk) + 1 );
Vec_PtrPush( pMan->vObjs, Hop_ManConst1(pMan) );
// map constant node and PIs
Abc_AigConst1(pNtk)->pNext = (Abc_Obj_t *)Hop_ManConst1(pMan);
Abc_NtkForEachCi( pNtk, pObj, i )
pObj->pNext = (Abc_Obj_t *)Hop_ObjCreatePi(pMan);
// map the internal nodes
Abc_AigForEachAnd( pNtk, pObj, i )
{
pObj->pNext = (Abc_Obj_t *)Hop_And( pMan, Hop_ObjChild0Next(pObj), Hop_ObjChild1Next(pObj) );
assert( !Abc_ObjIsComplement(pObj->pNext) );
}
// set the choice nodes
Abc_AigForEachAnd( pNtk, pObj, i )
{
if ( pObj->pCopy )
((Hop_Obj_t *)pObj->pNext)->pData = pObj->pCopy->pNext;
}
// transfer the POs
Abc_NtkForEachCo( pNtk, pObj, i )
Hop_ObjCreatePo( pMan, Hop_ObjChild0Next(pObj) );
// check the new manager
if ( !Hop_ManCheck(pMan) )
printf( "Abc_NtkPartStartHop: HOP manager check has failed.\n" );
return pMan;
}
/**Function*************************************************************
Synopsis [Stitches together several networks with choice nodes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Ntk_t * Abc_NtkPartStitchChoices( Abc_Ntk_t * pNtk, Vec_Ptr_t * vParts )
{
extern Abc_Ntk_t * Abc_NtkHopRemoveLoops( Abc_Ntk_t * pNtk, Hop_Man_t * pMan );
Hop_Man_t * pMan;
Vec_Ptr_t * vNodes;
Abc_Ntk_t * pNtkNew, * pNtkTemp;
Abc_Obj_t * pObj, * pFanin;
int i, k, iNodeId;
// start a new network similar to the original one
assert( Abc_NtkIsStrash(pNtk) );
pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG );
// annotate parts to point to the new network
Vec_PtrForEachEntry( Abc_Ntk_t *, vParts, pNtkTemp, i )
{
assert( Abc_NtkIsStrash(pNtkTemp) );
Abc_NtkCleanCopy( pNtkTemp );
// map the CI nodes
Abc_AigConst1(pNtkTemp)->pCopy = Abc_AigConst1(pNtkNew);
Abc_NtkForEachCi( pNtkTemp, pObj, k )
{
iNodeId = Nm_ManFindIdByNameTwoTypes( pNtkNew->pManName, Abc_ObjName(pObj), ABC_OBJ_PI, ABC_OBJ_BO );
if ( iNodeId == -1 )
{
printf( "Cannot find CI node %s in the original network.\n", Abc_ObjName(pObj) );
return NULL;
}
pObj->pCopy = Abc_NtkObj( pNtkNew, iNodeId );
}
// add the internal nodes while saving representatives
vNodes = Abc_AigDfs( pNtkTemp, 1, 0 );
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, k )
{
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
assert( !Abc_ObjIsComplement(pObj->pCopy) );
if ( Abc_AigNodeIsChoice(pObj) )
for ( pFanin = (Abc_Obj_t *)pObj->pData; pFanin; pFanin = (Abc_Obj_t *)pFanin->pData )
pFanin->pCopy->pCopy = pObj->pCopy;
}
Vec_PtrFree( vNodes );
// map the CO nodes
Abc_NtkForEachCo( pNtkTemp, pObj, k )
{
iNodeId = Nm_ManFindIdByNameTwoTypes( pNtkNew->pManName, Abc_ObjName(pObj), ABC_OBJ_PO, ABC_OBJ_BI );
if ( iNodeId == -1 )
{
printf( "Cannot find CO node %s in the original network.\n", Abc_ObjName(pObj) );
return NULL;
}
pObj->pCopy = Abc_NtkObj( pNtkNew, iNodeId );
Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
}
}
// connect the remaining POs
/*
Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
Abc_NtkForEachCi( pNtk, pObj, i )
pObj->pCopy = Abc_NtkCi( pNtkNew, i );
Abc_NtkForEachCo( pNtk, pObj, i )
pObj->pCopy = Abc_NtkCo( pNtkNew, i );
*/
Abc_NtkForEachCo( pNtk, pObj, i )
{
if ( Abc_ObjFaninNum(pObj->pCopy) == 0 )
Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
}
// transform into the HOP manager
pMan = Abc_NtkPartStartHop( pNtkNew );
pNtkNew = Abc_NtkHopRemoveLoops( pNtkTemp = pNtkNew, pMan );
Abc_NtkDelete( pNtkTemp );
// check correctness of the new network
if ( !Abc_NtkCheck( pNtkNew ) )
{
printf( "Abc_NtkPartStitchChoices: The network check has failed.\n" );
Abc_NtkDelete( pNtkNew );
return NULL;
}
return pNtkNew;
}
/**Function*************************************************************
Synopsis [Stitches together several networks with choice nodes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Ntk_t * Abc_NtkFraigPartitioned( Vec_Ptr_t * vStore, void * pParams )
{
Vec_Ptr_t * vParts, * vFraigs, * vOnePtr;
Vec_Int_t * vOne;
Abc_Ntk_t * pNtk, * pNtk2, * pNtkAig, * pNtkFraig;
int i, k;
// perform partitioning
pNtk = (Abc_Ntk_t *)Vec_PtrEntry( vStore, 0 );
assert( Abc_NtkIsStrash(pNtk) );
// vParts = Abc_NtkPartitionNaive( pNtk, 20 );
vParts = Abc_NtkPartitionSmart( pNtk, 300, 0 );
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "unset progressbar" );
// fraig each partition
vOnePtr = Vec_PtrAlloc( 1000 );
vFraigs = Vec_PtrAlloc( Vec_PtrSize(vParts) );
Vec_PtrForEachEntry( Vec_Int_t *, vParts, vOne, i )
{
// start the partition
Abc_NtkConvertCos( pNtk, vOne, vOnePtr );
pNtkAig = Abc_NtkCreateConeArray( pNtk, vOnePtr, 0 );
// add nodes to the partition
Vec_PtrForEachEntryStart( Abc_Ntk_t *, vStore, pNtk2, k, 1 )
{
Abc_NtkConvertCos( pNtk2, vOne, vOnePtr );
Abc_NtkAppendToCone( pNtkAig, pNtk2, vOnePtr );
}
printf( "Fraiging part %4d (out of %4d) PI = %5d. PO = %5d. And = %6d. Lev = %4d.\r",
i+1, Vec_PtrSize(vParts), Abc_NtkPiNum(pNtkAig), Abc_NtkPoNum(pNtkAig),
Abc_NtkNodeNum(pNtkAig), Abc_AigLevel(pNtkAig) );
// fraig the partition
pNtkFraig = Abc_NtkFraig( pNtkAig, pParams, 1, 0 );
Vec_PtrPush( vFraigs, pNtkFraig );
Abc_NtkDelete( pNtkAig );
}
printf( " \r" );
Vec_VecFree( (Vec_Vec_t *)vParts );
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "set progressbar" );
// derive the final network
pNtkFraig = Abc_NtkPartStitchChoices( pNtk, vFraigs );
Vec_PtrForEachEntry( Abc_Ntk_t *, vFraigs, pNtkAig, i )
Abc_NtkDelete( pNtkAig );
Vec_PtrFree( vFraigs );
Vec_PtrFree( vOnePtr );
return pNtkFraig;
}
/**Function*************************************************************
Synopsis [Stitches together several networks with choice nodes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkFraigPartitionedTime( Abc_Ntk_t * pNtk, void * pParams )
{
Vec_Ptr_t * vParts, * vFraigs, * vOnePtr;
Vec_Int_t * vOne;
Abc_Ntk_t * pNtkAig, * pNtkFraig;
int i;
abctime clk = Abc_Clock();
// perform partitioning
assert( Abc_NtkIsStrash(pNtk) );
// vParts = Abc_NtkPartitionNaive( pNtk, 20 );
vParts = Abc_NtkPartitionSmart( pNtk, 300, 0 );
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "unset progressbar" );
// fraig each partition
vOnePtr = Vec_PtrAlloc( 1000 );
vFraigs = Vec_PtrAlloc( Vec_PtrSize(vParts) );
Vec_PtrForEachEntry( Vec_Int_t *, vParts, vOne, i )
{
Abc_NtkConvertCos( pNtk, vOne, vOnePtr );
pNtkAig = Abc_NtkCreateConeArray( pNtk, vOnePtr, 0 );
pNtkFraig = Abc_NtkFraig( pNtkAig, pParams, 0, 0 );
Vec_PtrPush( vFraigs, pNtkFraig );
Abc_NtkDelete( pNtkAig );
printf( "Finished part %5d (out of %5d)\r", i+1, Vec_PtrSize(vParts) );
}
Vec_VecFree( (Vec_Vec_t *)vParts );
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "set progressbar" );
// derive the final network
Vec_PtrForEachEntry( Abc_Ntk_t *, vFraigs, pNtkAig, i )
Abc_NtkDelete( pNtkAig );
Vec_PtrFree( vFraigs );
Vec_PtrFree( vOnePtr );
ABC_PRT( "Partitioned fraiging time", Abc_Clock() - clk );
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END