blob: 6083c035edfb466ef72238740141e5a035dd7887 [file] [log] [blame]
/**CFile****************************************************************
FileName [darRefact.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [DAG-aware AIG rewriting.]
Synopsis [Refactoring.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - April 28, 2007.]
Revision [$Id: darRefact.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $]
***********************************************************************/
#include "darInt.h"
#include "bool/kit/kit.h"
#include "bool/bdc/bdc.h"
#include "bool/bdc/bdcInt.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
// the refactoring manager
typedef struct Ref_Man_t_ Ref_Man_t;
struct Ref_Man_t_
{
// input data
Dar_RefPar_t * pPars; // rewriting parameters
Aig_Man_t * pAig; // AIG manager
// computed cuts
Vec_Vec_t * vCuts; // the storage for cuts
// truth table and ISOP
Vec_Ptr_t * vTruthElem; // elementary truth tables
Vec_Ptr_t * vTruthStore; // storage for truth tables
Vec_Int_t * vMemory; // storage for ISOP
Vec_Ptr_t * vCutNodes; // storage for internal nodes of the cut
// various data members
Vec_Ptr_t * vLeavesBest; // the best set of leaves
Kit_Graph_t * pGraphBest; // the best factored form
int GainBest; // the best gain
int LevelBest; // the level of node with the best gain
// bi-decomposition
Bdc_Par_t DecPars; // decomposition parameters
Bdc_Man_t * pManDec; // decomposition manager
// node statistics
int nNodesInit; // the initial number of nodes
int nNodesTried; // the number of nodes tried
int nNodesBelow; // the number of nodes below the level limit
int nNodesExten; // the number of nodes with extended cut
int nCutsUsed; // the number of rewriting steps
int nCutsTried; // the number of cuts tries
// timing statistics
abctime timeCuts;
abctime timeEval;
abctime timeOther;
abctime timeTotal;
};
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Returns the structure with default assignment of parameters.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dar_ManDefaultRefParams( Dar_RefPar_t * pPars )
{
memset( pPars, 0, sizeof(Dar_RefPar_t) );
pPars->nMffcMin = 2; // the min MFFC size for which refactoring is used
pPars->nLeafMax = 12; // the max number of leaves of a cut
pPars->nCutsMax = 5; // the max number of cuts to consider
pPars->fUpdateLevel = 0;
pPars->fUseZeros = 0;
pPars->fVerbose = 0;
pPars->fVeryVerbose = 0;
}
/**Function*************************************************************
Synopsis [Starts the rewriting manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Ref_Man_t * Dar_ManRefStart( Aig_Man_t * pAig, Dar_RefPar_t * pPars )
{
Ref_Man_t * p;
// start the manager
p = ABC_ALLOC( Ref_Man_t, 1 );
memset( p, 0, sizeof(Ref_Man_t) );
p->pAig = pAig;
p->pPars = pPars;
// other data
p->vCuts = Vec_VecStart( pPars->nCutsMax );
p->vTruthElem = Vec_PtrAllocTruthTables( pPars->nLeafMax );
p->vTruthStore = Vec_PtrAllocSimInfo( 1024, Kit_TruthWordNum(pPars->nLeafMax) );
p->vMemory = Vec_IntAlloc( 1 << 16 );
p->vCutNodes = Vec_PtrAlloc( 256 );
p->vLeavesBest = Vec_PtrAlloc( pPars->nLeafMax );
// alloc bi-decomposition manager
p->DecPars.nVarsMax = pPars->nLeafMax;
p->DecPars.fVerbose = pPars->fVerbose;
p->DecPars.fVeryVerbose = 0;
// p->pManDec = Bdc_ManAlloc( &p->DecPars );
return p;
}
/**Function*************************************************************
Synopsis [Prints out the statistics of the manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dar_ManRefPrintStats( Ref_Man_t * p )
{
int Gain = p->nNodesInit - Aig_ManNodeNum(p->pAig);
printf( "NodesBeg = %8d. NodesEnd = %8d. Gain = %6d. (%6.2f %%).\n",
p->nNodesInit, Aig_ManNodeNum(p->pAig), Gain, 100.0*Gain/p->nNodesInit );
printf( "Tried = %6d. Below = %5d. Extended = %5d. Used = %5d. Levels = %4d.\n",
p->nNodesTried, p->nNodesBelow, p->nNodesExten, p->nCutsUsed, Aig_ManLevels(p->pAig) );
ABC_PRT( "Cuts ", p->timeCuts );
ABC_PRT( "Eval ", p->timeEval );
ABC_PRT( "Other ", p->timeOther );
ABC_PRT( "TOTAL ", p->timeTotal );
}
/**Function*************************************************************
Synopsis [Stops the rewriting manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dar_ManRefStop( Ref_Man_t * p )
{
if ( p->pManDec )
Bdc_ManFree( p->pManDec );
if ( p->pPars->fVerbose )
Dar_ManRefPrintStats( p );
Vec_VecFree( p->vCuts );
Vec_PtrFree( p->vTruthElem );
Vec_PtrFree( p->vTruthStore );
Vec_PtrFree( p->vLeavesBest );
Vec_IntFree( p->vMemory );
Vec_PtrFree( p->vCutNodes );
ABC_FREE( p );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ref_ObjComputeCuts( Aig_Man_t * pAig, Aig_Obj_t * pRoot, Vec_Vec_t * vCuts )
{
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ref_ObjPrint( Aig_Obj_t * pObj )
{
printf( "%d", pObj? Aig_Regular(pObj)->Id : -1 );
if ( pObj )
printf( "(%d) ", Aig_IsComplement(pObj) );
}
/**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 Dar_RefactTryGraph( Aig_Man_t * pAig, Aig_Obj_t * pRoot, Vec_Ptr_t * vCut, Kit_Graph_t * pGraph, int NodeMax, int LevelMax )
{
Kit_Node_t * pNode, * pNode0, * pNode1;
Aig_Obj_t * pAnd, * pAnd0, * pAnd1;
int i, Counter, LevelNew, LevelOld;
// check for constant function or a literal
if ( Kit_GraphIsConst(pGraph) || Kit_GraphIsVar(pGraph) )
return 0;
// set the levels of the leaves
Kit_GraphForEachLeaf( pGraph, pNode, i )
{
pNode->pFunc = Vec_PtrEntry(vCut, i);
pNode->Level = Aig_Regular((Aig_Obj_t *)pNode->pFunc)->Level;
assert( Aig_Regular((Aig_Obj_t *)pNode->pFunc)->Level < (1<<24)-1 );
}
//printf( "Trying:\n" );
// compute the AIG size after adding the internal nodes
Counter = 0;
Kit_GraphForEachNode( pGraph, pNode, i )
{
// get the children of this node
pNode0 = Kit_GraphNode( pGraph, pNode->eEdge0.Node );
pNode1 = Kit_GraphNode( pGraph, pNode->eEdge1.Node );
// get the AIG nodes corresponding to the children
pAnd0 = (Aig_Obj_t *)pNode0->pFunc;
pAnd1 = (Aig_Obj_t *)pNode1->pFunc;
if ( pAnd0 && pAnd1 )
{
// if they are both present, find the resulting node
pAnd0 = Aig_NotCond( pAnd0, pNode->eEdge0.fCompl );
pAnd1 = Aig_NotCond( pAnd1, pNode->eEdge1.fCompl );
pAnd = Aig_TableLookupTwo( pAig, pAnd0, pAnd1 );
// return -1 if the node is the same as the original root
if ( Aig_Regular(pAnd) == pRoot )
return -1;
}
else
pAnd = NULL;
// count the number of added nodes
if ( pAnd == NULL || Aig_ObjIsTravIdCurrent(pAig, Aig_Regular(pAnd)) )
{
if ( ++Counter > NodeMax )
return -1;
}
// count the number of new levels
LevelNew = 1 + Abc_MaxInt( pNode0->Level, pNode1->Level );
if ( pAnd )
{
if ( Aig_Regular(pAnd) == Aig_ManConst1(pAig) )
LevelNew = 0;
else if ( Aig_Regular(pAnd) == Aig_Regular(pAnd0) )
LevelNew = (int)Aig_Regular(pAnd0)->Level;
else if ( Aig_Regular(pAnd) == Aig_Regular(pAnd1) )
LevelNew = (int)Aig_Regular(pAnd1)->Level;
LevelOld = (int)Aig_Regular(pAnd)->Level;
// assert( LevelNew == LevelOld );
}
if ( LevelNew > LevelMax )
return -1;
pNode->pFunc = pAnd;
pNode->Level = LevelNew;
/*
printf( "Checking " );
Ref_ObjPrint( pAnd0 );
printf( " and " );
Ref_ObjPrint( pAnd1 );
printf( " Result " );
Ref_ObjPrint( pNode->pFunc );
printf( "\n" );
*/
}
return Counter;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Obj_t * Dar_RefactBuildGraph( Aig_Man_t * pAig, Vec_Ptr_t * vCut, Kit_Graph_t * pGraph )
{
Aig_Obj_t * pAnd0, * pAnd1;
Kit_Node_t * pNode = NULL;
int i;
// check for constant function
if ( Kit_GraphIsConst(pGraph) )
return Aig_NotCond( Aig_ManConst1(pAig), Kit_GraphIsComplement(pGraph) );
// set the leaves
Kit_GraphForEachLeaf( pGraph, pNode, i )
pNode->pFunc = Vec_PtrEntry(vCut, i);
// check for a literal
if ( Kit_GraphIsVar(pGraph) )
return Aig_NotCond( (Aig_Obj_t *)Kit_GraphVar(pGraph)->pFunc, Kit_GraphIsComplement(pGraph) );
// build the AIG nodes corresponding to the AND gates of the graph
//printf( "Building (current number %d):\n", Aig_ManObjNumMax(pAig) );
Kit_GraphForEachNode( pGraph, pNode, i )
{
pAnd0 = Aig_NotCond( (Aig_Obj_t *)Kit_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl );
pAnd1 = Aig_NotCond( (Aig_Obj_t *)Kit_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl );
pNode->pFunc = Aig_And( pAig, pAnd0, pAnd1 );
/*
printf( "Checking " );
Ref_ObjPrint( pAnd0 );
printf( " and " );
Ref_ObjPrint( pAnd1 );
printf( " Result " );
Ref_ObjPrint( pNode->pFunc );
printf( "\n" );
*/
}
// complement the result if necessary
return Aig_NotCond( (Aig_Obj_t *)pNode->pFunc, Kit_GraphIsComplement(pGraph) );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dar_ManRefactorTryCuts( Ref_Man_t * p, Aig_Obj_t * pObj, int nNodesSaved, int Required )
{
Vec_Ptr_t * vCut;
Kit_Graph_t * pGraphCur;
int k, RetValue, GainCur, nNodesAdded;
unsigned * pTruth;
p->GainBest = -1;
p->pGraphBest = NULL;
Vec_VecForEachLevel( p->vCuts, vCut, k )
{
if ( Vec_PtrSize(vCut) == 0 )
continue;
// if ( Vec_PtrSize(vCut) != 0 && Vec_PtrSize(Vec_VecEntry(p->vCuts, k+1)) != 0 )
// continue;
p->nCutsTried++;
// get the cut nodes
Aig_ObjCollectCut( pObj, vCut, p->vCutNodes );
// get the truth table
pTruth = Aig_ManCutTruth( pObj, vCut, p->vCutNodes, p->vTruthElem, p->vTruthStore );
if ( Kit_TruthIsConst0(pTruth, Vec_PtrSize(vCut)) )
{
p->GainBest = Aig_NodeMffcSupp( p->pAig, pObj, 0, NULL );
p->pGraphBest = Kit_GraphCreateConst0();
Vec_PtrCopy( p->vLeavesBest, vCut );
return p->GainBest;
}
if ( Kit_TruthIsConst1(pTruth, Vec_PtrSize(vCut)) )
{
p->GainBest = Aig_NodeMffcSupp( p->pAig, pObj, 0, NULL );
p->pGraphBest = Kit_GraphCreateConst1();
Vec_PtrCopy( p->vLeavesBest, vCut );
return p->GainBest;
}
// try the positive phase
RetValue = Kit_TruthIsop( pTruth, Vec_PtrSize(vCut), p->vMemory, 0 );
if ( RetValue > -1 )
{
pGraphCur = Kit_SopFactor( p->vMemory, 0, Vec_PtrSize(vCut), p->vMemory );
/*
{
int RetValue;
RetValue = Bdc_ManDecompose( p->pManDec, pTruth, NULL, Vec_PtrSize(vCut), NULL, 1000 );
printf( "Graph = %d. Bidec = %d.\n", Kit_GraphNodeNum(pGraphCur), RetValue );
}
*/
nNodesAdded = Dar_RefactTryGraph( p->pAig, pObj, vCut, pGraphCur, nNodesSaved - !p->pPars->fUseZeros, Required );
if ( nNodesAdded > -1 )
{
GainCur = nNodesSaved - nNodesAdded;
if ( p->GainBest < GainCur || (p->GainBest == GainCur &&
(Kit_GraphIsConst(pGraphCur) || Kit_GraphRootLevel(pGraphCur) < Kit_GraphRootLevel(p->pGraphBest))) )
{
p->GainBest = GainCur;
if ( p->pGraphBest )
Kit_GraphFree( p->pGraphBest );
p->pGraphBest = pGraphCur;
Vec_PtrCopy( p->vLeavesBest, vCut );
}
else
Kit_GraphFree( pGraphCur );
}
else
Kit_GraphFree( pGraphCur );
}
// try negative phase
Kit_TruthNot( pTruth, pTruth, Vec_PtrSize(vCut) );
RetValue = Kit_TruthIsop( pTruth, Vec_PtrSize(vCut), p->vMemory, 0 );
// Kit_TruthNot( pTruth, pTruth, Vec_PtrSize(vCut) );
if ( RetValue > -1 )
{
pGraphCur = Kit_SopFactor( p->vMemory, 1, Vec_PtrSize(vCut), p->vMemory );
/*
{
int RetValue;
RetValue = Bdc_ManDecompose( p->pManDec, pTruth, NULL, Vec_PtrSize(vCut), NULL, 1000 );
printf( "Graph = %d. Bidec = %d.\n", Kit_GraphNodeNum(pGraphCur), RetValue );
}
*/
nNodesAdded = Dar_RefactTryGraph( p->pAig, pObj, vCut, pGraphCur, nNodesSaved - !p->pPars->fUseZeros, Required );
if ( nNodesAdded > -1 )
{
GainCur = nNodesSaved - nNodesAdded;
if ( p->GainBest < GainCur || (p->GainBest == GainCur &&
(Kit_GraphIsConst(pGraphCur) || Kit_GraphRootLevel(pGraphCur) < Kit_GraphRootLevel(p->pGraphBest))) )
{
p->GainBest = GainCur;
if ( p->pGraphBest )
Kit_GraphFree( p->pGraphBest );
p->pGraphBest = pGraphCur;
Vec_PtrCopy( p->vLeavesBest, vCut );
}
else
Kit_GraphFree( pGraphCur );
}
else
Kit_GraphFree( pGraphCur );
}
}
return p->GainBest;
}
/**Function*************************************************************
Synopsis [Returns 1 if a non-PI node has nLevelMin or below.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dar_ObjCutLevelAchieved( Vec_Ptr_t * vCut, int nLevelMin )
{
Aig_Obj_t * pObj;
int i;
Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i )
if ( !Aig_ObjIsCi(pObj) && (int)pObj->Level <= nLevelMin )
return 1;
return 0;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dar_ManRefactor( Aig_Man_t * pAig, Dar_RefPar_t * pPars )
{
// Bar_Progress_t * pProgress;
Ref_Man_t * p;
Vec_Ptr_t * vCut, * vCut2;
Aig_Obj_t * pObj, * pObjNew;
int nNodesOld, nNodeBefore, nNodeAfter, nNodesSaved, nNodesSaved2;
int i, Required, nLevelMin;
abctime clkStart, clk;
// start the manager
p = Dar_ManRefStart( pAig, pPars );
// remove dangling nodes
Aig_ManCleanup( pAig );
// if updating levels is requested, start fanout and timing
Aig_ManFanoutStart( pAig );
if ( p->pPars->fUpdateLevel )
Aig_ManStartReverseLevels( pAig, 0 );
// resynthesize each node once
clkStart = Abc_Clock();
vCut = Vec_VecEntry( p->vCuts, 0 );
vCut2 = Vec_VecEntry( p->vCuts, 1 );
p->nNodesInit = Aig_ManNodeNum(pAig);
nNodesOld = Vec_PtrSize( pAig->vObjs );
// pProgress = Bar_ProgressStart( stdout, nNodesOld );
Aig_ManForEachObj( pAig, pObj, i )
{
// Bar_ProgressUpdate( pProgress, i, NULL );
if ( !Aig_ObjIsNode(pObj) )
continue;
if ( i > nNodesOld )
break;
if ( pAig->Time2Quit && !(i & 256) && Abc_Clock() > pAig->Time2Quit )
break;
Vec_VecClear( p->vCuts );
//printf( "\nConsidering node %d.\n", pObj->Id );
// get the bounded MFFC size
clk = Abc_Clock();
nLevelMin = Abc_MaxInt( 0, Aig_ObjLevel(pObj) - 10 );
nNodesSaved = Aig_NodeMffcSupp( pAig, pObj, nLevelMin, vCut );
if ( nNodesSaved < p->pPars->nMffcMin ) // too small to consider
{
p->timeCuts += Abc_Clock() - clk;
continue;
}
p->nNodesTried++;
if ( Vec_PtrSize(vCut) > p->pPars->nLeafMax ) // get one reconv-driven cut
{
Aig_ManFindCut( pObj, vCut, p->vCutNodes, p->pPars->nLeafMax, 50 );
nNodesSaved = Aig_NodeMffcLabelCut( p->pAig, pObj, vCut );
}
else if ( Vec_PtrSize(vCut) < p->pPars->nLeafMax - 2 && p->pPars->fExtend )
{
if ( !Dar_ObjCutLevelAchieved(vCut, nLevelMin) )
{
if ( Aig_NodeMffcExtendCut( pAig, pObj, vCut, vCut2 ) )
{
nNodesSaved2 = Aig_NodeMffcLabelCut( p->pAig, pObj, vCut );
assert( nNodesSaved2 == nNodesSaved );
}
if ( Vec_PtrSize(vCut2) > p->pPars->nLeafMax )
Vec_PtrClear(vCut2);
if ( Vec_PtrSize(vCut2) > 0 )
{
p->nNodesExten++;
// printf( "%d(%d) ", Vec_PtrSize(vCut), Vec_PtrSize(vCut2) );
}
}
else
p->nNodesBelow++;
}
p->timeCuts += Abc_Clock() - clk;
// try the cuts
clk = Abc_Clock();
Required = pAig->vLevelR? Aig_ObjRequiredLevel(pAig, pObj) : ABC_INFINITY;
Dar_ManRefactorTryCuts( p, pObj, nNodesSaved, Required );
p->timeEval += Abc_Clock() - clk;
// check the best gain
if ( !(p->GainBest > 0 || (p->GainBest == 0 && p->pPars->fUseZeros)) )
{
if ( p->pGraphBest )
Kit_GraphFree( p->pGraphBest );
continue;
}
//printf( "\n" );
// if we end up here, a rewriting step is accepted
nNodeBefore = Aig_ManNodeNum( pAig );
pObjNew = Dar_RefactBuildGraph( pAig, p->vLeavesBest, p->pGraphBest );
assert( (int)Aig_Regular(pObjNew)->Level <= Required );
// replace the node
Aig_ObjReplace( pAig, pObj, pObjNew, p->pPars->fUpdateLevel );
// compare the gains
nNodeAfter = Aig_ManNodeNum( pAig );
assert( p->GainBest <= nNodeBefore - nNodeAfter );
Kit_GraphFree( p->pGraphBest );
p->nCutsUsed++;
// break;
}
p->timeTotal = Abc_Clock() - clkStart;
p->timeOther = p->timeTotal - p->timeCuts - p->timeEval;
// Bar_ProgressStop( pProgress );
// put the nodes into the DFS order and reassign their IDs
// Aig_NtkReassignIds( p );
// fix the levels
Aig_ManFanoutStop( pAig );
if ( p->pPars->fUpdateLevel )
Aig_ManStopReverseLevels( pAig );
/*
Aig_ManForEachObj( p->pAig, pObj, i )
if ( Aig_ObjIsNode(pObj) && Aig_ObjRefs(pObj) == 0 )
{
printf( "Unreferenced " );
Aig_ObjPrintVerbose( pObj, 0 );
printf( "\n" );
}
*/
// remove dangling nodes (they should not be here!)
Aig_ManCleanup( pAig );
// stop the rewriting manager
Dar_ManRefStop( p );
// Aig_ManCheckPhase( pAig );
if ( !Aig_ManCheck( pAig ) )
{
printf( "Dar_ManRefactor: The network check has failed.\n" );
return 0;
}
return 1;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END