blob: 0ffe2d15cb3cd5b4807bb1e608f4ecfda26788c7 [file] [log] [blame]
/**CFile****************************************************************
FileName [ivySeq.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [And-Inverter Graph package.]
Synopsis []
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - May 11, 2006.]
Revision [$Id: ivySeq.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
***********************************************************************/
#include "ivy.h"
#include "bool/deco/deco.h"
#include "opt/rwt/rwt.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static int Ivy_NodeRewriteSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUseZeroCost );
static void Ivy_GraphPrepare( Dec_Graph_t * pGraph, Ivy_Cut_t * pCut, Vec_Ptr_t * vFanins, char * pPerm );
static unsigned Ivy_CutGetTruth( Ivy_Man_t * p, Ivy_Obj_t * pObj, int * pNums, int nNums );
static Dec_Graph_t * Rwt_CutEvaluateSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pRoot, Ivy_Cut_t * pCut, char * pPerm, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int * pGainBest, unsigned uTruth );
static int Ivy_GraphToNetworkSeqCountSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax );
static Ivy_Obj_t * Ivy_GraphToNetworkSeq( Ivy_Man_t * p, Dec_Graph_t * pGraph );
static void Ivy_GraphUpdateNetworkSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int nGain );
static Ivy_Store_t * Ivy_CutComputeForNode( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves );
static inline int Ivy_CutHashValue( int NodeId ) { return 1 << (NodeId % 31); }
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
//int nMoves;
//int nMovesS;
//int nClauses;
//int timeInv;
/**Function*************************************************************
Synopsis [Performs incremental rewriting of the AIG.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_ManRewriteSeq( Ivy_Man_t * p, int fUseZeroCost, int fVerbose )
{
Rwt_Man_t * pManRwt;
Ivy_Obj_t * pNode;
int i, nNodes, nGain;
abctime clk, clkStart = Abc_Clock();
// set the DC latch values
Ivy_ManForEachLatch( p, pNode, i )
pNode->Init = IVY_INIT_DC;
// start the rewriting manager
pManRwt = Rwt_ManStart( 0 );
p->pData = pManRwt;
if ( pManRwt == NULL )
return 0;
// create fanouts
if ( p->fFanout == 0 )
Ivy_ManStartFanout( p );
// resynthesize each node once
nNodes = Ivy_ManObjIdMax(p);
Ivy_ManForEachNode( p, pNode, i )
{
assert( !Ivy_ObjIsBuf(pNode) );
assert( !Ivy_ObjIsBuf(Ivy_ObjFanin0(pNode)) );
assert( !Ivy_ObjIsBuf(Ivy_ObjFanin1(pNode)) );
// fix the fanin buffer problem
// Ivy_NodeFixBufferFanins( p, pNode );
// if ( Ivy_ObjIsBuf(pNode) )
// continue;
// stop if all nodes have been tried once
if ( i > nNodes )
break;
// for each cut, try to resynthesize it
nGain = Ivy_NodeRewriteSeq( p, pManRwt, pNode, fUseZeroCost );
if ( nGain > 0 || (nGain == 0 && fUseZeroCost) )
{
Dec_Graph_t * pGraph = (Dec_Graph_t *)Rwt_ManReadDecs(pManRwt);
int fCompl = Rwt_ManReadCompl(pManRwt);
// complement the FF if needed
clk = Abc_Clock();
if ( fCompl ) Dec_GraphComplement( pGraph );
Ivy_GraphUpdateNetworkSeq( p, pNode, pGraph, nGain );
if ( fCompl ) Dec_GraphComplement( pGraph );
Rwt_ManAddTimeUpdate( pManRwt, Abc_Clock() - clk );
}
}
Rwt_ManAddTimeTotal( pManRwt, Abc_Clock() - clkStart );
// print stats
if ( fVerbose )
Rwt_ManPrintStats( pManRwt );
// delete the managers
Rwt_ManStop( pManRwt );
p->pData = NULL;
// fix the levels
Ivy_ManResetLevels( p );
// if ( Ivy_ManCheckFanoutNums(p) )
// printf( "Ivy_ManRewritePre(): The check has failed.\n" );
// check
if ( !Ivy_ManCheck(p) )
printf( "Ivy_ManRewritePre(): The check has failed.\n" );
return 1;
}
/**Function*************************************************************
Synopsis [Performs rewriting for one node.]
Description [This procedure considers all the cuts computed for the node
and tries to rewrite each of them using the "forest" of different AIG
structures precomputed and stored in the RWR manager.
Determines the best rewriting and computes the gain in the number of AIG
nodes in the final network. In the end, p->vFanins contains information
about the best cut that can be used for rewriting, while p->pGraph gives
the decomposition dag (represented using decomposition graph data structure).
Returns gain in the number of nodes or -1 if node cannot be rewritten.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_NodeRewriteSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUseZeroCost )
{
int fVeryVerbose = 0;
Dec_Graph_t * pGraph;
Ivy_Store_t * pStore;
Ivy_Cut_t * pCut;
Ivy_Obj_t * pFanin;//, * pFanout;
Vec_Ptr_t * vFanout;
unsigned uPhase;
unsigned uTruthBest = 0; // Suppress "might be used uninitialized"
unsigned uTruth;//, nNewClauses;
char * pPerm;
int nNodesSaved;
int nNodesSaveCur = -1; // Suppress "might be used uninitialized"
int i, c, GainCur = -1, GainBest = -1;
abctime clk, clk2;//, clk3;
p->nNodesConsidered++;
// get the node's cuts
clk = Abc_Clock();
pStore = Ivy_CutComputeForNode( pMan, pNode, 5 );
p->timeCut += Abc_Clock() - clk;
// go through the cuts
clk = Abc_Clock();
vFanout = Vec_PtrAlloc( 100 );
for ( c = 1; c < pStore->nCuts; c++ )
{
pCut = pStore->pCuts + c;
// consider only 4-input cuts
if ( pCut->nSize != 4 )
continue;
// skip the cuts with buffers
for ( i = 0; i < (int)pCut->nSize; i++ )
if ( Ivy_ObjIsBuf( Ivy_ManObj(pMan, Ivy_LeafId(pCut->pArray[i])) ) )
break;
if ( i != pCut->nSize )
{
p->nCutsBad++;
continue;
}
p->nCutsGood++;
// get the fanin permutation
clk2 = Abc_Clock();
uTruth = 0xFFFF & Ivy_CutGetTruth( pMan, pNode, pCut->pArray, pCut->nSize ); // truth table
p->timeTruth += Abc_Clock() - clk2;
pPerm = p->pPerms4[ (int)p->pPerms[uTruth] ];
uPhase = p->pPhases[uTruth];
// collect fanins with the corresponding permutation/phase
Vec_PtrClear( p->vFaninsCur );
Vec_PtrFill( p->vFaninsCur, (int)pCut->nSize, 0 );
for ( i = 0; i < (int)pCut->nSize; i++ )
{
pFanin = Ivy_ManObj( pMan, Ivy_LeafId( pCut->pArray[(int)pPerm[i]] ) );
assert( Ivy_ObjIsNode(pFanin) || Ivy_ObjIsCi(pFanin) || Ivy_ObjIsConst1(pFanin) );
pFanin = Ivy_NotCond(pFanin, ((uPhase & (1<<i)) > 0) );
Vec_PtrWriteEntry( p->vFaninsCur, i, pFanin );
}
clk2 = Abc_Clock();
// mark the fanin boundary
Vec_PtrForEachEntry( Ivy_Obj_t *, p->vFaninsCur, pFanin, i )
Ivy_ObjRefsInc( Ivy_Regular(pFanin) );
// label MFFC with current ID
Ivy_ManIncrementTravId( pMan );
nNodesSaved = Ivy_ObjMffcLabel( pMan, pNode );
// label fanouts with the current ID
// Ivy_ObjForEachFanout( pMan, pNode, vFanout, pFanout, i )
// Ivy_ObjSetTravIdCurrent( pMan, pFanout );
// unmark the fanin boundary
Vec_PtrForEachEntry( Ivy_Obj_t *, p->vFaninsCur, pFanin, i )
Ivy_ObjRefsDec( Ivy_Regular(pFanin) );
p->timeMffc += Abc_Clock() - clk2;
// evaluate the cut
clk2 = Abc_Clock();
pGraph = Rwt_CutEvaluateSeq( pMan, p, pNode, pCut, pPerm, p->vFaninsCur, nNodesSaved, &GainCur, uTruth );
p->timeEval += Abc_Clock() - clk2;
// check if the cut is better than the current best one
if ( pGraph != NULL && GainBest < GainCur )
{
// save this form
nNodesSaveCur = nNodesSaved;
GainBest = GainCur;
p->pGraph = pGraph;
p->pCut = pCut;
p->pPerm = pPerm;
p->fCompl = ((uPhase & (1<<4)) > 0);
uTruthBest = uTruth;
// collect fanins in the
Vec_PtrClear( p->vFanins );
Vec_PtrForEachEntry( Ivy_Obj_t *, p->vFaninsCur, pFanin, i )
Vec_PtrPush( p->vFanins, pFanin );
}
}
Vec_PtrFree( vFanout );
p->timeRes += Abc_Clock() - clk;
if ( GainBest == -1 )
return -1;
/*
{
Ivy_Cut_t * pCut = p->pCut;
printf( "Node %5d. Using cut : {", Ivy_ObjId(pNode) );
for ( i = 0; i < pCut->nSize; i++ )
printf( " %d(%d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
printf( " }\n" );
}
*/
//clk3 = Abc_Clock();
//nNewClauses = Ivy_CutTruthPrint( pMan, p->pCut, uTruth );
//timeInv += Abc_Clock() - clk;
// nClauses += nNewClauses;
// nMoves++;
// if ( nNewClauses > 0 )
// nMovesS++;
// copy the leaves
Ivy_GraphPrepare( (Dec_Graph_t *)p->pGraph, (Ivy_Cut_t *)p->pCut, p->vFanins, p->pPerm );
p->nScores[p->pMap[uTruthBest]]++;
p->nNodesGained += GainBest;
if ( fUseZeroCost || GainBest > 0 )
p->nNodesRewritten++;
/*
if ( GainBest > 0 )
{
Ivy_Cut_t * pCut = p->pCut;
printf( "Node %5d. Using cut : {", Ivy_ObjId(pNode) );
for ( i = 0; i < pCut->nSize; i++ )
printf( " %5d(%2d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
printf( " }\n" );
}
*/
// report the progress
if ( fVeryVerbose && GainBest > 0 )
{
printf( "Node %6d : ", Ivy_ObjId(pNode) );
printf( "Fanins = %d. ", p->vFanins->nSize );
printf( "Save = %d. ", nNodesSaveCur );
printf( "Add = %d. ", nNodesSaveCur-GainBest );
printf( "GAIN = %d. ", GainBest );
printf( "Cone = %d. ", p->pGraph? Dec_GraphNodeNum((Dec_Graph_t *)p->pGraph) : 0 );
printf( "Class = %d. ", p->pMap[uTruthBest] );
printf( "\n" );
}
return GainBest;
}
/**Function*************************************************************
Synopsis [Evaluates the cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Rwt_CutEvaluateSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pRoot, Ivy_Cut_t * pCut, char * pPerm, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int * pGainBest, unsigned uTruth )
{
Vec_Ptr_t * vSubgraphs;
Dec_Graph_t * pGraphBest = NULL; // Suppress "might be used uninitialized"
Dec_Graph_t * pGraphCur;
Rwt_Node_t * pNode;
int nNodesAdded, GainBest, i;
// find the matching class of subgraphs
vSubgraphs = Vec_VecEntry( p->vClasses, p->pMap[uTruth] );
p->nSubgraphs += vSubgraphs->nSize;
// determine the best subgraph
GainBest = -1;
Vec_PtrForEachEntry( Rwt_Node_t *, vSubgraphs, pNode, i )
{
// get the current graph
pGraphCur = (Dec_Graph_t *)pNode->pNext;
// if ( pRoot->Id == 8648 )
// Dec_GraphPrint( stdout, pGraphCur, NULL, NULL );
// copy the leaves
// Vec_PtrForEachEntry( Ivy_Obj_t *, vFaninsCur, pFanin, k )
// Dec_GraphNode(pGraphCur, k)->pFunc = pFanin;
Ivy_GraphPrepare( pGraphCur, pCut, vFaninsCur, pPerm );
// detect how many unlabeled nodes will be reused
nNodesAdded = Ivy_GraphToNetworkSeqCountSeq( pMan, pRoot, pGraphCur, nNodesSaved );
if ( nNodesAdded == -1 )
continue;
assert( nNodesSaved >= nNodesAdded );
// count the gain at this node
if ( GainBest < nNodesSaved - nNodesAdded )
{
GainBest = nNodesSaved - nNodesAdded;
pGraphBest = pGraphCur;
}
}
if ( GainBest == -1 )
return NULL;
*pGainBest = GainBest;
return pGraphBest;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_GraphPrepare( Dec_Graph_t * pGraph, Ivy_Cut_t * pCut, Vec_Ptr_t * vFanins, char * pPerm )
{
Dec_Node_t * pNode, * pNode0, * pNode1;
int i;
assert( Dec_GraphLeaveNum(pGraph) == pCut->nSize );
assert( Vec_PtrSize(vFanins) == pCut->nSize );
// label the leaves with latch numbers
Dec_GraphForEachLeaf( pGraph, pNode, i )
{
pNode->pFunc = Vec_PtrEntry( vFanins, i );
pNode->nLat2 = Ivy_LeafLat( pCut->pArray[(int)pPerm[i]] );
}
// propagate latches through the nodes
Dec_GraphForEachNode( pGraph, pNode, i )
{
// get the children of this node
pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node );
pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node );
// distribute the latches
pNode->nLat2 = IVY_MIN( pNode0->nLat2, pNode1->nLat2 );
pNode->nLat0 = pNode0->nLat2 - pNode->nLat2;
pNode->nLat1 = pNode1->nLat2 - pNode->nLat2;
}
}
/**Function*************************************************************
Synopsis [Counts the number of new nodes added when using this graph.]
Description [AIG nodes for the fanins should be assigned to pNode->pFunc
of the leaves of the graph before calling this procedure.
Returns -1 if the number of nodes and levels exceeded the given limit or
the number of levels exceeded the maximum allowed level.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_GraphToNetworkSeqCountSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax )
{
Dec_Node_t * pNode, * pNode0, * pNode1;
Ivy_Obj_t * pAnd, * pAnd0, * pAnd1;
int i, k, Counter, fCompl;
// check for constant function or a literal
if ( Dec_GraphIsConst(pGraph) || Dec_GraphIsVar(pGraph) )
return 0;
// compute the AIG size after adding the internal nodes
Counter = 0;
Dec_GraphForEachNode( pGraph, pNode, i )
{
// get the children of this node
pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node );
pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node );
// get the AIG nodes corresponding to the children
pAnd0 = (Ivy_Obj_t *)pNode0->pFunc;
pAnd1 = (Ivy_Obj_t *)pNode1->pFunc;
// skip the latches
for ( k = 0; pAnd0 && k < (int)pNode->nLat0; k++ )
{
fCompl = Ivy_IsComplement(pAnd0);
pAnd0 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Regular(pAnd0), NULL, IVY_LATCH, IVY_INIT_DC) );
if ( pAnd0 )
pAnd0 = Ivy_NotCond( pAnd0, fCompl );
}
for ( k = 0; pAnd1 && k < (int)pNode->nLat1; k++ )
{
fCompl = Ivy_IsComplement(pAnd1);
pAnd1 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Regular(pAnd1), NULL, IVY_LATCH, IVY_INIT_DC) );
if ( pAnd1 )
pAnd1 = Ivy_NotCond( pAnd1, fCompl );
}
// get the new node
if ( pAnd0 && pAnd1 )
{
// if they are both present, find the resulting node
pAnd0 = Ivy_NotCond( pAnd0, pNode->eEdge0.fCompl );
pAnd1 = Ivy_NotCond( pAnd1, pNode->eEdge1.fCompl );
assert( !Ivy_ObjIsLatch(Ivy_Regular(pAnd0)) || !Ivy_ObjIsLatch(Ivy_Regular(pAnd1)) );
if ( Ivy_Regular(pAnd0) == Ivy_Regular(pAnd1) || Ivy_ObjIsConst1(Ivy_Regular(pAnd0)) || Ivy_ObjIsConst1(Ivy_Regular(pAnd1)) )
pAnd = Ivy_And( p, pAnd0, pAnd1 );
else
pAnd = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, pAnd0, pAnd1, IVY_AND, IVY_INIT_NONE) );
// return -1 if the node is the same as the original root
if ( Ivy_Regular(pAnd) == pRoot )
return -1;
}
else
pAnd = NULL;
// count the number of added nodes
if ( pAnd == NULL || Ivy_ObjIsTravIdCurrent(p, Ivy_Regular(pAnd)) )
{
if ( ++Counter > NodeMax )
return -1;
}
pNode->pFunc = pAnd;
}
return Counter;
}
/**Function*************************************************************
Synopsis [Transforms the decomposition graph into the AIG.]
Description [AIG nodes for the fanins should be assigned to pNode->pFunc
of the leaves of the graph before calling this procedure.]
SideEffects []
SeeAlso []
***********************************************************************/
Ivy_Obj_t * Ivy_GraphToNetworkSeq( Ivy_Man_t * p, Dec_Graph_t * pGraph )
{
Ivy_Obj_t * pAnd0, * pAnd1;
Dec_Node_t * pNode = NULL; // Suppress "might be used uninitialized"
int i, k;
// check for constant function
if ( Dec_GraphIsConst(pGraph) )
return Ivy_NotCond( Ivy_ManConst1(p), Dec_GraphIsComplement(pGraph) );
// check for a literal
if ( Dec_GraphIsVar(pGraph) )
{
// get the variable node
pNode = Dec_GraphVar(pGraph);
// add the remaining latches
for ( k = 0; k < (int)pNode->nLat2; k++ )
pNode->pFunc = Ivy_Latch( p, (Ivy_Obj_t *)pNode->pFunc, IVY_INIT_DC );
return Ivy_NotCond( (Ivy_Obj_t *)pNode->pFunc, Dec_GraphIsComplement(pGraph) );
}
// build the AIG nodes corresponding to the AND gates of the graph
Dec_GraphForEachNode( pGraph, pNode, i )
{
pAnd0 = Ivy_NotCond( (Ivy_Obj_t *)Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl );
pAnd1 = Ivy_NotCond( (Ivy_Obj_t *)Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl );
// add the latches
for ( k = 0; k < (int)pNode->nLat0; k++ )
pAnd0 = Ivy_Latch( p, pAnd0, IVY_INIT_DC );
for ( k = 0; k < (int)pNode->nLat1; k++ )
pAnd1 = Ivy_Latch( p, pAnd1, IVY_INIT_DC );
// create the node
pNode->pFunc = Ivy_And( p, pAnd0, pAnd1 );
}
// add the remaining latches
for ( k = 0; k < (int)pNode->nLat2; k++ )
pNode->pFunc = Ivy_Latch( p, (Ivy_Obj_t *)pNode->pFunc, IVY_INIT_DC );
// complement the result if necessary
return Ivy_NotCond( (Ivy_Obj_t *)pNode->pFunc, Dec_GraphIsComplement(pGraph) );
}
/**Function*************************************************************
Synopsis [Replaces MFFC of the node by the new factored form.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_GraphUpdateNetworkSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int nGain )
{
Ivy_Obj_t * pRootNew;
int nNodesNew, nNodesOld;
nNodesOld = Ivy_ManNodeNum(p);
// create the new structure of nodes
pRootNew = Ivy_GraphToNetworkSeq( p, pGraph );
Ivy_ObjReplace( p, pRoot, pRootNew, 1, 0, 0 );
// compare the gains
nNodesNew = Ivy_ManNodeNum(p);
assert( nGain <= nNodesOld - nNodesNew );
// propagate the buffer
Ivy_ManPropagateBuffers( p, 0 );
}
/**Function*************************************************************
Synopsis [Computes the truth table.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
unsigned Ivy_CutGetTruth_rec( Ivy_Man_t * p, int Leaf, int * pNums, int nNums )
{
static unsigned uMasks[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };
unsigned uTruth0, uTruth1;
Ivy_Obj_t * pObj;
int i;
for ( i = 0; i < nNums; i++ )
if ( Leaf == pNums[i] )
return uMasks[i];
pObj = Ivy_ManObj( p, Ivy_LeafId(Leaf) );
if ( Ivy_ObjIsLatch(pObj) )
{
assert( !Ivy_ObjFaninC0(pObj) );
Leaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pObj), Ivy_LeafLat(Leaf) + 1 );
return Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
}
assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsBuf(pObj) );
Leaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pObj), Ivy_LeafLat(Leaf) );
uTruth0 = Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
if ( Ivy_ObjFaninC0(pObj) )
uTruth0 = ~uTruth0;
if ( Ivy_ObjIsBuf(pObj) )
return uTruth0;
Leaf = Ivy_LeafCreate( Ivy_ObjFaninId1(pObj), Ivy_LeafLat(Leaf) );
uTruth1 = Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
if ( Ivy_ObjFaninC1(pObj) )
uTruth1 = ~uTruth1;
return uTruth0 & uTruth1;
}
/**Function*************************************************************
Synopsis [Computes the truth table.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
unsigned Ivy_CutGetTruth( Ivy_Man_t * p, Ivy_Obj_t * pObj, int * pNums, int nNums )
{
assert( Ivy_ObjIsNode(pObj) );
assert( nNums < 6 );
return Ivy_CutGetTruth_rec( p, Ivy_LeafCreate(pObj->Id, 0), pNums, nNums );
}
/**Function*************************************************************
Synopsis [Returns 1 if the cut can be constructed; 0 otherwise.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Ivy_CutPrescreen( Ivy_Cut_t * pCut, int Id0, int Id1 )
{
int i;
if ( pCut->nSize < pCut->nSizeMax )
return 1;
for ( i = 0; i < pCut->nSize; i++ )
if ( pCut->pArray[i] == Id0 || pCut->pArray[i] == Id1 )
return 1;
return 0;
}
/**Function*************************************************************
Synopsis [Derives new cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Ivy_CutDeriveNew2( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
{
unsigned uHash = 0;
int i, k;
assert( pCut->nSize > 0 );
assert( IdNew0 < IdNew1 );
for ( i = k = 0; i < pCut->nSize; i++ )
{
if ( pCut->pArray[i] == IdOld )
continue;
if ( IdNew0 >= 0 )
{
if ( IdNew0 <= pCut->pArray[i] )
{
if ( IdNew0 < pCut->pArray[i] )
{
if ( k == pCut->nSizeMax )
return 0;
pCutNew->pArray[ k++ ] = IdNew0;
uHash |= Ivy_CutHashValue( IdNew0 );
}
IdNew0 = -1;
}
}
if ( IdNew1 >= 0 )
{
if ( IdNew1 <= pCut->pArray[i] )
{
if ( IdNew1 < pCut->pArray[i] )
{
if ( k == pCut->nSizeMax )
return 0;
pCutNew->pArray[ k++ ] = IdNew1;
uHash |= Ivy_CutHashValue( IdNew1 );
}
IdNew1 = -1;
}
}
if ( k == pCut->nSizeMax )
return 0;
pCutNew->pArray[ k++ ] = pCut->pArray[i];
uHash |= Ivy_CutHashValue( pCut->pArray[i] );
}
if ( IdNew0 >= 0 )
{
if ( k == pCut->nSizeMax )
return 0;
pCutNew->pArray[ k++ ] = IdNew0;
uHash |= Ivy_CutHashValue( IdNew0 );
}
if ( IdNew1 >= 0 )
{
if ( k == pCut->nSizeMax )
return 0;
pCutNew->pArray[ k++ ] = IdNew1;
uHash |= Ivy_CutHashValue( IdNew1 );
}
pCutNew->nSize = k;
pCutNew->uHash = uHash;
assert( pCutNew->nSize <= pCut->nSizeMax );
for ( i = 1; i < pCutNew->nSize; i++ )
assert( pCutNew->pArray[i-1] < pCutNew->pArray[i] );
return 1;
}
/**Function*************************************************************
Synopsis [Derives new cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Ivy_CutDeriveNew( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
{
unsigned uHash = 0;
int i, k;
assert( pCut->nSize > 0 );
assert( IdNew0 < IdNew1 );
for ( i = k = 0; i < pCut->nSize; i++ )
{
if ( pCut->pArray[i] == IdOld )
continue;
if ( IdNew0 <= pCut->pArray[i] )
{
if ( IdNew0 < pCut->pArray[i] )
{
pCutNew->pArray[ k++ ] = IdNew0;
uHash |= Ivy_CutHashValue( IdNew0 );
}
IdNew0 = 0x7FFFFFFF;
}
if ( IdNew1 <= pCut->pArray[i] )
{
if ( IdNew1 < pCut->pArray[i] )
{
pCutNew->pArray[ k++ ] = IdNew1;
uHash |= Ivy_CutHashValue( IdNew1 );
}
IdNew1 = 0x7FFFFFFF;
}
pCutNew->pArray[ k++ ] = pCut->pArray[i];
uHash |= Ivy_CutHashValue( pCut->pArray[i] );
}
if ( IdNew0 < 0x7FFFFFFF )
{
pCutNew->pArray[ k++ ] = IdNew0;
uHash |= Ivy_CutHashValue( IdNew0 );
}
if ( IdNew1 < 0x7FFFFFFF )
{
pCutNew->pArray[ k++ ] = IdNew1;
uHash |= Ivy_CutHashValue( IdNew1 );
}
pCutNew->nSize = k;
pCutNew->uHash = uHash;
assert( pCutNew->nSize <= pCut->nSizeMax );
// for ( i = 1; i < pCutNew->nSize; i++ )
// assert( pCutNew->pArray[i-1] < pCutNew->pArray[i] );
return 1;
}
/**Function*************************************************************
Synopsis [Find the hash value of the cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline unsigned Ivy_NodeCutHash( Ivy_Cut_t * pCut )
{
int i;
pCut->uHash = 0;
for ( i = 0; i < pCut->nSize; i++ )
pCut->uHash |= (1 << (pCut->pArray[i] % 31));
return pCut->uHash;
}
/**Function*************************************************************
Synopsis [Derives new cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Ivy_CutDeriveNew3( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
{
int i, k;
assert( pCut->nSize > 0 );
assert( IdNew0 < IdNew1 );
for ( i = k = 0; i < pCut->nSize; i++ )
{
if ( pCut->pArray[i] == IdOld )
continue;
if ( IdNew0 <= pCut->pArray[i] )
{
if ( IdNew0 < pCut->pArray[i] )
pCutNew->pArray[ k++ ] = IdNew0;
IdNew0 = 0x7FFFFFFF;
}
if ( IdNew1 <= pCut->pArray[i] )
{
if ( IdNew1 < pCut->pArray[i] )
pCutNew->pArray[ k++ ] = IdNew1;
IdNew1 = 0x7FFFFFFF;
}
pCutNew->pArray[ k++ ] = pCut->pArray[i];
}
if ( IdNew0 < 0x7FFFFFFF )
pCutNew->pArray[ k++ ] = IdNew0;
if ( IdNew1 < 0x7FFFFFFF )
pCutNew->pArray[ k++ ] = IdNew1;
pCutNew->nSize = k;
assert( pCutNew->nSize <= pCut->nSizeMax );
Ivy_NodeCutHash( pCutNew );
return 1;
}
/**Function*************************************************************
Synopsis [Returns 1 if pDom is contained in pCut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Ivy_CutCheckDominance( Ivy_Cut_t * pDom, Ivy_Cut_t * pCut )
{
int i, k;
for ( i = 0; i < pDom->nSize; i++ )
{
assert( i==0 || pDom->pArray[i-1] < pDom->pArray[i] );
for ( k = 0; k < pCut->nSize; k++ )
if ( pDom->pArray[i] == pCut->pArray[k] )
break;
if ( k == pCut->nSize ) // node i in pDom is not contained in pCut
return 0;
}
// every node in pDom is contained in pCut
return 1;
}
/**Function*************************************************************
Synopsis [Check if the cut exists.]
Description [Returns 1 if the cut exists.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_CutFindOrAddFilter( Ivy_Store_t * pCutStore, Ivy_Cut_t * pCutNew )
{
Ivy_Cut_t * pCut;
int i, k;
assert( pCutNew->uHash );
// try to find the cut
for ( i = 0; i < pCutStore->nCuts; i++ )
{
pCut = pCutStore->pCuts + i;
if ( pCut->nSize == 0 )
continue;
if ( pCut->nSize == pCutNew->nSize )
{
if ( pCut->uHash == pCutNew->uHash )
{
for ( k = 0; k < pCutNew->nSize; k++ )
if ( pCut->pArray[k] != pCutNew->pArray[k] )
break;
if ( k == pCutNew->nSize )
return 1;
}
continue;
}
if ( pCut->nSize < pCutNew->nSize )
{
// skip the non-contained cuts
if ( (pCut->uHash & pCutNew->uHash) != pCut->uHash )
continue;
// check containment seriously
if ( Ivy_CutCheckDominance( pCut, pCutNew ) )
return 1;
continue;
}
// check potential containment of other cut
// skip the non-contained cuts
if ( (pCut->uHash & pCutNew->uHash) != pCutNew->uHash )
continue;
// check containment seriously
if ( Ivy_CutCheckDominance( pCutNew, pCut ) )
{
// remove the current cut
pCut->nSize = 0;
}
}
assert( pCutStore->nCuts < pCutStore->nCutsMax );
// add the cut
pCut = pCutStore->pCuts + pCutStore->nCuts++;
*pCut = *pCutNew;
return 0;
}
/**Function*************************************************************
Synopsis [Compresses the cut representation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_CutCompactAll( Ivy_Store_t * pCutStore )
{
Ivy_Cut_t * pCut;
int i, k;
pCutStore->nCutsM = 0;
for ( i = k = 0; i < pCutStore->nCuts; i++ )
{
pCut = pCutStore->pCuts + i;
if ( pCut->nSize == 0 )
continue;
if ( pCut->nSize < pCut->nSizeMax )
pCutStore->nCutsM++;
pCutStore->pCuts[k++] = *pCut;
}
pCutStore->nCuts = k;
}
/**Function*************************************************************
Synopsis [Print the cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_CutPrintForNode( Ivy_Cut_t * pCut )
{
int i;
assert( pCut->nSize > 0 );
printf( "%d : {", pCut->nSize );
for ( i = 0; i < pCut->nSize; i++ )
printf( " %d", pCut->pArray[i] );
printf( " }\n" );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_CutPrintForNodes( Ivy_Store_t * pCutStore )
{
int i;
printf( "Node %d\n", pCutStore->pCuts[0].pArray[0] );
for ( i = 0; i < pCutStore->nCuts; i++ )
Ivy_CutPrintForNode( pCutStore->pCuts + i );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Ivy_CutReadLeaf( Ivy_Obj_t * pFanin )
{
int nLats, iLeaf;
assert( !Ivy_IsComplement(pFanin) );
if ( !Ivy_ObjIsLatch(pFanin) )
return Ivy_LeafCreate( pFanin->Id, 0 );
iLeaf = Ivy_CutReadLeaf(Ivy_ObjFanin0(pFanin));
nLats = Ivy_LeafLat(iLeaf);
assert( nLats < IVY_LEAF_MASK );
return 1 + iLeaf;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Ivy_Store_t * Ivy_CutComputeForNode( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves )
{
static Ivy_Store_t CutStore, * pCutStore = &CutStore;
Ivy_Cut_t CutNew, * pCutNew = &CutNew, * pCut;
Ivy_Obj_t * pLeaf;
int i, k, Temp, nLats, iLeaf0, iLeaf1;
assert( nLeaves <= IVY_CUT_INPUT );
// start the structure
pCutStore->nCuts = 0;
pCutStore->nCutsMax = IVY_CUT_LIMIT;
// start the trivial cut
pCutNew->uHash = 0;
pCutNew->nSize = 1;
pCutNew->nSizeMax = nLeaves;
pCutNew->pArray[0] = Ivy_LeafCreate( pObj->Id, 0 );
pCutNew->uHash = Ivy_CutHashValue( pCutNew->pArray[0] );
// add the trivial cut
pCutStore->pCuts[pCutStore->nCuts++] = *pCutNew;
assert( pCutStore->nCuts == 1 );
// explore the cuts
for ( i = 0; i < pCutStore->nCuts; i++ )
{
// expand this cut
pCut = pCutStore->pCuts + i;
if ( pCut->nSize == 0 )
continue;
for ( k = 0; k < pCut->nSize; k++ )
{
pLeaf = Ivy_ManObj( p, Ivy_LeafId(pCut->pArray[k]) );
if ( Ivy_ObjIsCi(pLeaf) || Ivy_ObjIsConst1(pLeaf) )
continue;
assert( Ivy_ObjIsNode(pLeaf) );
nLats = Ivy_LeafLat(pCut->pArray[k]);
// get the fanins fanins
iLeaf0 = Ivy_CutReadLeaf( Ivy_ObjFanin0(pLeaf) );
iLeaf1 = Ivy_CutReadLeaf( Ivy_ObjFanin1(pLeaf) );
assert( nLats + Ivy_LeafLat(iLeaf0) < IVY_LEAF_MASK && nLats + Ivy_LeafLat(iLeaf1) < IVY_LEAF_MASK );
iLeaf0 = nLats + iLeaf0;
iLeaf1 = nLats + iLeaf1;
if ( !Ivy_CutPrescreen( pCut, iLeaf0, iLeaf1 ) )
continue;
// the given cut exist
if ( iLeaf0 > iLeaf1 )
Temp = iLeaf0, iLeaf0 = iLeaf1, iLeaf1 = Temp;
// create the new cut
if ( !Ivy_CutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf0, iLeaf1 ) )
continue;
// add the cut
Ivy_CutFindOrAddFilter( pCutStore, pCutNew );
if ( pCutStore->nCuts == IVY_CUT_LIMIT )
break;
}
if ( pCutStore->nCuts == IVY_CUT_LIMIT )
break;
}
if ( pCutStore->nCuts == IVY_CUT_LIMIT )
pCutStore->fSatur = 1;
else
pCutStore->fSatur = 0;
// printf( "%d ", pCutStore->nCuts );
Ivy_CutCompactAll( pCutStore );
// printf( "%d \n", pCutStore->nCuts );
// Ivy_CutPrintForNodes( pCutStore );
return pCutStore;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_CutComputeAll( Ivy_Man_t * p, int nInputs )
{
Ivy_Store_t * pStore;
Ivy_Obj_t * pObj;
int i, nCutsTotal, nCutsTotalM, nNodeTotal, nNodeOver;
abctime clk = Abc_Clock();
if ( nInputs > IVY_CUT_INPUT )
{
printf( "Cannot compute cuts for more than %d inputs.\n", IVY_CUT_INPUT );
return;
}
nNodeTotal = nNodeOver = 0;
nCutsTotal = nCutsTotalM = -Ivy_ManNodeNum(p);
Ivy_ManForEachObj( p, pObj, i )
{
if ( !Ivy_ObjIsNode(pObj) )
continue;
pStore = Ivy_CutComputeForNode( p, pObj, nInputs );
nCutsTotal += pStore->nCuts;
nCutsTotalM += pStore->nCutsM;
nNodeOver += pStore->fSatur;
nNodeTotal++;
}
printf( "All = %6d. Minus = %6d. Triv = %6d. Node = %6d. Satur = %6d. ",
nCutsTotal, nCutsTotalM, Ivy_ManPiNum(p) + Ivy_ManNodeNum(p), nNodeTotal, nNodeOver );
ABC_PRT( "Time", Abc_Clock() - clk );
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END