blob: ef5dd451446fe6dfb45a60d8fa70f1d80431e517 [file] [log] [blame]
/**CFile****************************************************************
FileName [abcRestruct.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Network and node package.]
Synopsis []
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: abcRestruct.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "base/abc/abc.h"
#include "bool/dec/dec.h"
#include "opt/cut/cut.h"
#ifdef ABC_USE_CUDD
#include "bdd/extrab/extraBdd.h"
#include "bdd/dsd/dsd.h"
#endif
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
#ifdef ABC_USE_CUDD
#define RST_RANDOM_UNSIGNED ((((unsigned)rand()) << 24) ^ (((unsigned)rand()) << 12) ^ ((unsigned)rand()))
typedef struct Abc_ManRst_t_ Abc_ManRst_t;
struct Abc_ManRst_t_
{
// the network
Abc_Ntk_t * pNtk; // the network for restructuring
// user specified parameters
int nCutMax; // the limit on the size of the supernode
int fUpdateLevel; // turns on watching the number of levels
int fUseZeros; // turns on zero-cost replacements
int fVerbose; // the verbosity flag
// internal data structures
DdManager * dd; // the BDD manager
Dsd_Manager_t * pManDsd; // the DSD manager
Vec_Ptr_t * vVisited; // temporary
Vec_Ptr_t * vLeaves; // temporary
Vec_Ptr_t * vDecs; // temporary
Vec_Ptr_t * vTemp; // temporary
Vec_Int_t * vSims; // temporary
Vec_Int_t * vRands; // temporary
Vec_Int_t * vOnes; // temporary
Vec_Int_t * vBinate; // temporary
Vec_Int_t * vTwos; // temporary
// node statistics
int nLastGain;
int nCutsConsidered;
int nCutsExplored;
int nNodesConsidered;
int nNodesRestructured;
int nNodesGained;
// runtime statistics
int timeCut;
int timeBdd;
int timeDsd;
int timeEval;
int timeRes;
int timeNtk;
int timeTotal;
};
static Dec_Graph_t * Abc_NodeResubstitute( Abc_ManRst_t * p, Abc_Obj_t * pNode, Cut_Cut_t * pCutList );
static Dec_Graph_t * Abc_NodeRestructure( Abc_ManRst_t * p, Abc_Obj_t * pNode, Cut_Cut_t * pCutList );
static Dec_Graph_t * Abc_NodeRestructureCut( Abc_ManRst_t * p, Abc_Obj_t * pNode, Cut_Cut_t * pCut );
static Dec_Graph_t * Abc_NodeEvaluateDsd( Abc_ManRst_t * pManRst, Dsd_Node_t * pNodeDsd, Abc_Obj_t * pRoot, int Required, int nNodesSaved, int * pnNodesAdded );
static Cut_Man_t * Abc_NtkStartCutManForRestruct( Abc_Ntk_t * pNtk, int nCutMax, int fDag );
static Abc_ManRst_t * Abc_NtkManRstStart( int nCutMax, int fUpdateLevel, int fUseZeros, int fVerbose );
static void Abc_NtkManRstStop( Abc_ManRst_t * p );
static void Abc_NtkManRstPrintStats( Abc_ManRst_t * p );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Implements AIG restructuring.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkRestructure( Abc_Ntk_t * pNtk, int nCutMax, int fUpdateLevel, int fUseZeros, int fVerbose )
{
extern void Dec_GraphUpdateNetwork( Abc_Obj_t * pRoot, Dec_Graph_t * pGraph, int fUpdateLevel, int nGain );
ProgressBar * pProgress;
Abc_ManRst_t * pManRst;
Cut_Man_t * pManCut;
Cut_Cut_t * pCutList;
Dec_Graph_t * pGraph;
Abc_Obj_t * pNode;
abctime clk, clkStart = Abc_Clock();
int fMulti = 1;
int fResub = 0;
int i, nNodes;
assert( Abc_NtkIsStrash(pNtk) );
// cleanup the AIG
Abc_AigCleanup((Abc_Aig_t *)pNtk->pManFunc);
Abc_NtkCleanCopy(pNtk);
// compute the reverse levels if level update is requested
if ( fUpdateLevel )
Abc_NtkStartReverseLevels( pNtk, 0 );
// start the restructuring manager
pManRst = Abc_NtkManRstStart( nCutMax, fUpdateLevel, fUseZeros, fVerbose );
pManRst->pNtk = pNtk;
// start the cut manager
clk = Abc_Clock();
pManCut = Abc_NtkStartCutManForRestruct( pNtk, nCutMax, fMulti );
pManRst->timeCut += Abc_Clock() - clk;
// pNtk->pManCut = pManCut;
// resynthesize each node once
nNodes = Abc_NtkObjNumMax(pNtk);
pProgress = Extra_ProgressBarStart( stdout, nNodes );
Abc_NtkForEachNode( pNtk, pNode, i )
{
Extra_ProgressBarUpdate( pProgress, i, NULL );
// skip the constant node
// if ( Abc_NodeIsConst(pNode) )
// continue;
// skip persistant nodes
if ( Abc_NodeIsPersistant(pNode) )
continue;
// skip the node if it is inside the tree
// if ( Abc_ObjFanoutNum(pNode) < 2 )
// continue;
// skip the nodes with too many fanouts
if ( Abc_ObjFanoutNum(pNode) > 1000 )
continue;
// stop if all nodes have been tried once
if ( i >= nNodes )
break;
// get the cuts for the given node
clk = Abc_Clock();
pCutList = (Cut_Cut_t *)Abc_NodeGetCutsRecursive( pManCut, pNode, fMulti, 0 );
pManRst->timeCut += Abc_Clock() - clk;
// perform restructuring
clk = Abc_Clock();
if ( fResub )
pGraph = Abc_NodeResubstitute( pManRst, pNode, pCutList );
else
pGraph = Abc_NodeRestructure( pManRst, pNode, pCutList );
pManRst->timeRes += Abc_Clock() - clk;
if ( pGraph == NULL )
continue;
// acceptable replacement found, update the graph
clk = Abc_Clock();
Dec_GraphUpdateNetwork( pNode, pGraph, fUpdateLevel, pManRst->nLastGain );
pManRst->timeNtk += Abc_Clock() - clk;
Dec_GraphFree( pGraph );
}
Extra_ProgressBarStop( pProgress );
pManRst->timeTotal = Abc_Clock() - clkStart;
// print statistics of the manager
// if ( fVerbose )
Abc_NtkManRstPrintStats( pManRst );
// delete the managers
Cut_ManStop( pManCut );
Abc_NtkManRstStop( pManRst );
// put the nodes into the DFS order and reassign their IDs
Abc_NtkReassignIds( pNtk );
// Abc_AigCheckFaninOrder( pNtk->pManFunc );
// fix the levels
if ( fUpdateLevel )
Abc_NtkStopReverseLevels( pNtk );
else
Abc_NtkLevel( pNtk );
// check
if ( !Abc_NtkCheck( pNtk ) )
{
printf( "Abc_NtkRefactor: The network check has failed.\n" );
return 0;
}
return 1;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_RestructNodeDivisors( Abc_ManRst_t * p, Abc_Obj_t * pRoot, int nNodesSaved )
{
Abc_Obj_t * pNode, * pFanout;//, * pFanin;
int i, k;
// start with the leaves
Vec_PtrClear( p->vDecs );
Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pNode, i )
{
Vec_PtrPush( p->vDecs, pNode );
assert( pNode->fMarkC == 0 );
pNode->fMarkC = 1;
}
// explore the fanouts
Vec_PtrForEachEntry( Abc_Obj_t *, p->vDecs, pNode, i )
{
// if the fanout has both fanins in the set, add it
Abc_ObjForEachFanout( pNode, pFanout, k )
{
if ( pFanout->fMarkC || Abc_ObjIsPo(pFanout) )
continue;
if ( Abc_ObjFanin0(pFanout)->fMarkC && Abc_ObjFanin1(pFanout)->fMarkC )
{
Vec_PtrPush( p->vDecs, pFanout );
pFanout->fMarkC = 1;
}
}
}
// unmark the nodes
Vec_PtrForEachEntry( Abc_Obj_t *, p->vDecs, pNode, i )
pNode->fMarkC = 0;
/*
// print the nodes
Vec_PtrForEachEntryStart( Abc_Obj_t *, p->vDecs, pNode, i, Vec_PtrSize(p->vLeaves) )
{
printf( "%2d %s = ", i, Abc_NodeIsTravIdCurrent(pNode)? "*" : " " );
// find the first fanin
Vec_PtrForEachEntry( Abc_Obj_t *, p->vDecs, pFanin, k )
if ( Abc_ObjFanin0(pNode) == pFanin )
break;
if ( k < Vec_PtrSize(p->vLeaves) )
printf( "%c", 'a' + k );
else
printf( "%d", k );
printf( "%s ", Abc_ObjFaninC0(pNode)? "\'" : "" );
// find the second fanin
Vec_PtrForEachEntry( Abc_Obj_t *, p->vDecs, pFanin, k )
if ( Abc_ObjFanin1(pNode) == pFanin )
break;
if ( k < Vec_PtrSize(p->vLeaves) )
printf( "%c", 'a' + k );
else
printf( "%d", k );
printf( "%s ", Abc_ObjFaninC1(pNode)? "\'" : "" );
printf( "\n" );
}
*/
printf( "%d\n", Vec_PtrSize(p->vDecs)-nNodesSaved-Vec_PtrSize(p->vLeaves) );
}
/**Function*************************************************************
Synopsis [Starts the cut manager for rewriting.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeRestructure( Abc_ManRst_t * p, Abc_Obj_t * pNode, Cut_Cut_t * pCutList )
{
Dec_Graph_t * pGraph;
Cut_Cut_t * pCut;
// int nCuts;
p->nNodesConsidered++;
/*
// count the number of cuts with four inputs or more
nCuts = 0;
for ( pCut = pCutList; pCut; pCut = pCut->pNext )
nCuts += (int)(pCut->nLeaves > 3);
printf( "-----------------------------------\n" );
printf( "Node %6d : Factor-cuts = %5d.\n", pNode->Id, nCuts );
*/
// go through the interesting cuts
for ( pCut = pCutList; pCut; pCut = pCut->pNext )
{
if ( pCut->nLeaves < 4 )
continue;
if ( (pGraph = Abc_NodeRestructureCut( p, pNode, pCut )) )
return pGraph;
}
return NULL;
}
/**Function*************************************************************
Synopsis [Starts the cut manager for rewriting.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeRestructureCut( Abc_ManRst_t * p, Abc_Obj_t * pRoot, Cut_Cut_t * pCut )
{
extern DdNode * Abc_NodeConeBdd( DdManager * dd, DdNode ** pbVars, Abc_Obj_t * pNode, Vec_Ptr_t * vFanins, Vec_Ptr_t * vVisited );
Dec_Graph_t * pGraph;
Dsd_Node_t * pNodeDsd;
Abc_Obj_t * pLeaf;
DdNode * bFunc;
int nNodesSaved, nNodesAdded;
int Required, nMaxSize, clk, i;
int fVeryVerbose = 0;
p->nCutsConsidered++;
// get the required time for the node
Required = p->fUpdateLevel? Abc_ObjRequiredLevel(pRoot) : ABC_INFINITY;
// collect the leaves of the cut
Vec_PtrClear( p->vLeaves );
for ( i = 0; i < (int)pCut->nLeaves; i++ )
{
pLeaf = Abc_NtkObj(pRoot->pNtk, pCut->pLeaves[i]);
if ( pLeaf == NULL ) // the so-called "bad cut phenomenon" is due to removed nodes
return NULL;
Vec_PtrPush( p->vLeaves, pLeaf );
}
clk = Abc_Clock();
// collect the internal nodes of the cut
// Abc_NodeConeCollect( &pRoot, 1, p->vLeaves, p->vVisited, 0 );
// derive the BDD of the cut
bFunc = Abc_NodeConeBdd( p->dd, p->dd->vars, pRoot, p->vLeaves, p->vVisited ); Cudd_Ref( bFunc );
p->timeBdd += Abc_Clock() - clk;
// consider the special case, when the function is a constant
if ( Cudd_IsConstant(bFunc) )
{
p->nLastGain = Abc_NodeMffcSize( pRoot );
p->nNodesGained += p->nLastGain;
p->nNodesRestructured++;
Cudd_RecursiveDeref( p->dd, bFunc );
if ( Cudd_IsComplement(bFunc) )
return Dec_GraphCreateConst0();
return Dec_GraphCreateConst1();
}
clk = Abc_Clock();
// try disjoint support decomposition
pNodeDsd = Dsd_DecomposeOne( p->pManDsd, bFunc );
p->timeDsd += Abc_Clock() - clk;
// skip nodes with non-decomposable blocks
Dsd_TreeNodeGetInfoOne( pNodeDsd, NULL, &nMaxSize );
if ( nMaxSize > 3 )
{
Cudd_RecursiveDeref( p->dd, bFunc );
return NULL;
}
/*
// skip nodes that cannot be improved
if ( Vec_PtrSize(p->vVisited) <= Dsd_TreeGetAigCost(pNodeDsd) )
{
Cudd_RecursiveDeref( p->dd, bFunc );
return NULL;
}
*/
p->nCutsExplored++;
// mark the fanin boundary
// (can mark only essential fanins, belonging to bNodeFunc!)
Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pLeaf, i )
pLeaf->vFanouts.nSize++;
// label MFFC with current traversal ID
Abc_NtkIncrementTravId( pRoot->pNtk );
nNodesSaved = Abc_NodeMffcLabelAig( pRoot );
// unmark the fanin boundary and set the fanins as leaves in the form
Vec_PtrForEachEntry( Abc_Obj_t *, p->vLeaves, pLeaf, i )
pLeaf->vFanouts.nSize--;
/*
if ( nNodesSaved < 3 )
{
Cudd_RecursiveDeref( p->dd, bFunc );
return NULL;
}
*/
/*
printf( "%5d : Cut-size = %d. Old AIG = %2d. New AIG = %2d. Old MFFC = %2d.\n",
pRoot->Id, pCut->nLeaves, Vec_PtrSize(p->vVisited), Dsd_TreeGetAigCost(pNodeDsd),
nNodesSaved );
Dsd_NodePrint( stdout, pNodeDsd );
Abc_RestructNodeDivisors( p, pRoot );
if ( pRoot->Id == 433 )
{
int x = 0;
}
*/
// Abc_RestructNodeDivisors( p, pRoot, nNodesSaved );
// detect how many new nodes will be added (while taking into account reused nodes)
clk = Abc_Clock();
if ( nMaxSize > 3 )
pGraph = NULL;
else
pGraph = Abc_NodeEvaluateDsd( p, pNodeDsd, pRoot, Required, nNodesSaved, &nNodesAdded );
// pGraph = NULL;
p->timeEval += Abc_Clock() - clk;
// quit if there is no improvement
if ( pGraph == NULL || nNodesAdded == -1 || (nNodesAdded == nNodesSaved && !p->fUseZeros) )
{
Cudd_RecursiveDeref( p->dd, bFunc );
if ( pGraph ) Dec_GraphFree( pGraph );
return NULL;
}
/*
// print stats
printf( "%5d : Cut-size = %d. Old AIG = %2d. New AIG = %2d. Old MFFC = %2d. New MFFC = %2d. Gain = %d.\n",
pRoot->Id, pCut->nLeaves, Vec_PtrSize(p->vVisited), Dsd_TreeGetAigCost(pNodeDsd),
nNodesSaved, nNodesAdded, (nNodesAdded == -1)? 0 : nNodesSaved-nNodesAdded );
// Dsd_NodePrint( stdout, pNodeDsd );
// Dec_GraphPrint( stdout, pGraph, NULL, NULL );
*/
// compute the total gain in the number of nodes
p->nLastGain = nNodesSaved - nNodesAdded;
p->nNodesGained += p->nLastGain;
p->nNodesRestructured++;
// report the progress
if ( fVeryVerbose )
{
printf( "Node %6s : ", Abc_ObjName(pRoot) );
printf( "Cone = %2d. ", p->vLeaves->nSize );
printf( "BDD = %2d. ", Cudd_DagSize(bFunc) );
printf( "FF = %2d. ", 1 + Dec_GraphNodeNum(pGraph) );
printf( "MFFC = %2d. ", nNodesSaved );
printf( "Add = %2d. ", nNodesAdded );
printf( "GAIN = %2d. ", p->nLastGain );
printf( "\n" );
}
Cudd_RecursiveDeref( p->dd, bFunc );
return pGraph;
}
/**Function*************************************************************
Synopsis [Moves closer to the end the node that is best for sharing.]
Description [If the flag is set, tries to find an EXOR, otherwise, tries
to find an OR.]
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NodeEdgeDsdPermute( Dec_Graph_t * pGraph, Abc_ManRst_t * pManRst, Vec_Int_t * vEdges, int fExor )
{
Dec_Edge_t eNode1, eNode2, eNode3;
Abc_Obj_t * pNode1, * pNode2, * pNode3, * pTemp;
int LeftBound = 0, RightBound, i;
// get the right bound
RightBound = Vec_IntSize(vEdges) - 2;
assert( LeftBound <= RightBound );
if ( LeftBound == RightBound )
return;
// get the two last nodes
eNode1 = Dec_IntToEdge( Vec_IntEntry(vEdges, RightBound + 1) );
eNode2 = Dec_IntToEdge( Vec_IntEntry(vEdges, RightBound ) );
pNode1 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode1.Node )->pFunc;
pNode2 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode2.Node )->pFunc;
pNode1 = !pNode1? NULL : Abc_ObjNotCond( pNode1, eNode1.fCompl );
pNode2 = !pNode2? NULL : Abc_ObjNotCond( pNode2, eNode2.fCompl );
// quit if the last node does not exist
if ( pNode1 == NULL )
return;
// find the first node that can be shared
for ( i = RightBound; i >= LeftBound; i-- )
{
// get the third node
eNode3 = Dec_IntToEdge( Vec_IntEntry(vEdges, i) );
pNode3 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode3.Node )->pFunc;
pNode3 = !pNode3? NULL : Abc_ObjNotCond( pNode3, eNode3.fCompl );
if ( pNode3 == NULL )
continue;
// check if the node exists
if ( fExor )
{
if ( pNode1 && pNode3 )
{
pTemp = Abc_AigXorLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, pNode1, pNode3, NULL );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
continue;
if ( pNode3 == pNode2 )
return;
Vec_IntWriteEntry( vEdges, i, Dec_EdgeToInt(eNode2) );
Vec_IntWriteEntry( vEdges, RightBound, Dec_EdgeToInt(eNode3) );
return;
}
}
else
{
if ( pNode1 && pNode3 )
{
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, Abc_ObjNot(pNode1), Abc_ObjNot(pNode3) );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
continue;
if ( eNode3.Node == eNode2.Node )
return;
Vec_IntWriteEntry( vEdges, i, Dec_EdgeToInt(eNode2) );
Vec_IntWriteEntry( vEdges, RightBound, Dec_EdgeToInt(eNode3) );
return;
}
}
}
}
/**Function*************************************************************
Synopsis [Adds the new edge in the given order.]
Description [Similar to Vec_IntPushOrder, except in decreasing order.]
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NodeEdgeDsdPushOrdered( Dec_Graph_t * pGraph, Vec_Int_t * vEdges, int Edge )
{
int i, NodeOld, NodeNew;
vEdges->nSize++;
for ( i = vEdges->nSize-2; i >= 0; i-- )
{
NodeOld = Dec_IntToEdge(vEdges->pArray[i]).Node;
NodeNew = Dec_IntToEdge(Edge).Node;
// use <= because we are trying to push the new (non-existent) nodes as far as possible
if ( Dec_GraphNode(pGraph, NodeOld)->Level <= Dec_GraphNode(pGraph, NodeNew)->Level )
vEdges->pArray[i+1] = vEdges->pArray[i];
else
break;
}
vEdges->pArray[i+1] = Edge;
}
/**Function*************************************************************
Synopsis [Evaluation one DSD.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Edge_t Abc_NodeEvaluateDsd_rec( Dec_Graph_t * pGraph, Abc_ManRst_t * pManRst, Dsd_Node_t * pNodeDsd, int Required, int nNodesSaved, int * pnNodesAdded )
{
Dec_Edge_t eNode1, eNode2, eNode3, eResult, eQuit = { 0, 2006 };
Abc_Obj_t * pNode1, * pNode2, * pNode3, * pNode4, * pTemp;
Dsd_Node_t * pChildDsd;
Dsd_Type_t DecType;
Vec_Int_t * vEdges;
int Level1, Level2, Level3, Level4;
int i, Index, fCompl, Type;
// remove the complemented attribute
fCompl = Dsd_IsComplement( pNodeDsd );
pNodeDsd = Dsd_Regular( pNodeDsd );
// consider the trivial case
DecType = Dsd_NodeReadType( pNodeDsd );
if ( DecType == DSD_NODE_BUF )
{
Index = Dsd_NodeReadFunc(pNodeDsd)->index;
assert( Index < Dec_GraphLeaveNum(pGraph) );
eResult = Dec_EdgeCreate( Index, fCompl );
return eResult;
}
assert( DecType == DSD_NODE_OR || DecType == DSD_NODE_EXOR || DecType == DSD_NODE_PRIME );
// solve the problem for the children
vEdges = Vec_IntAlloc( Dsd_NodeReadDecsNum(pNodeDsd) );
Dsd_NodeForEachChild( pNodeDsd, i, pChildDsd )
{
eResult = Abc_NodeEvaluateDsd_rec( pGraph, pManRst, pChildDsd, Required, nNodesSaved, pnNodesAdded );
if ( eResult.Node == eQuit.Node ) // infeasible
{
Vec_IntFree( vEdges );
return eQuit;
}
// order the inputs only if this is OR or EXOR
if ( DecType == DSD_NODE_PRIME )
Vec_IntPush( vEdges, Dec_EdgeToInt(eResult) );
else
Abc_NodeEdgeDsdPushOrdered( pGraph, vEdges, Dec_EdgeToInt(eResult) );
}
// the edges are sorted by the level of their nodes in decreasing order
// consider special cases
if ( DecType == DSD_NODE_OR )
{
// try to balance the nodes by delay
assert( Vec_IntSize(vEdges) > 1 );
while ( Vec_IntSize(vEdges) > 1 )
{
// permute the last two entries
if ( Vec_IntSize(vEdges) > 2 )
Abc_NodeEdgeDsdPermute( pGraph, pManRst, vEdges, 0 );
// get the two last nodes
eNode1 = Dec_IntToEdge( Vec_IntPop(vEdges) );
eNode2 = Dec_IntToEdge( Vec_IntPop(vEdges) );
pNode1 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode1.Node )->pFunc;
pNode2 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode2.Node )->pFunc;
pNode1 = !pNode1? NULL : Abc_ObjNotCond( pNode1, eNode1.fCompl );
pNode2 = !pNode2? NULL : Abc_ObjNotCond( pNode2, eNode2.fCompl );
// check if the new node exists
pNode3 = NULL;
if ( pNode1 && pNode2 )
{
pNode3 = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, Abc_ObjNot(pNode1), Abc_ObjNot(pNode2) );
pNode3 = !pNode3? NULL : Abc_ObjNot(pNode3);
}
// create the new node
eNode3 = Dec_GraphAddNodeOr( pGraph, eNode1, eNode2 );
// set level
Level1 = Dec_GraphNode( pGraph, eNode1.Node )->Level;
Level2 = Dec_GraphNode( pGraph, eNode2.Node )->Level;
Dec_GraphNode( pGraph, eNode3.Node )->Level = 1 + Abc_MaxInt(Level1, Level2);
// get the new node if possible
if ( pNode3 )
{
Dec_GraphNode( pGraph, eNode3.Node )->pFunc = Abc_ObjNotCond(pNode3, eNode3.fCompl);
Level3 = Dec_GraphNode( pGraph, eNode3.Node )->Level;
assert( Required == ABC_INFINITY || Level3 == (int)Abc_ObjRegular(pNode3)->Level );
}
if ( !pNode3 || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pNode3)) )
{
(*pnNodesAdded)++;
if ( *pnNodesAdded > nNodesSaved )
{
Vec_IntFree( vEdges );
return eQuit;
}
}
// add the resulting node to the form
Abc_NodeEdgeDsdPushOrdered( pGraph, vEdges, Dec_EdgeToInt(eNode3) );
}
// get the last node
eResult = Dec_IntToEdge( Vec_IntPop(vEdges) );
Vec_IntFree( vEdges );
// complement the graph if the node was complemented
eResult.fCompl ^= fCompl;
return eResult;
}
if ( DecType == DSD_NODE_EXOR )
{
// try to balance the nodes by delay
assert( Vec_IntSize(vEdges) > 1 );
while ( Vec_IntSize(vEdges) > 1 )
{
// permute the last two entries
if ( Vec_IntSize(vEdges) > 2 )
Abc_NodeEdgeDsdPermute( pGraph, pManRst, vEdges, 1 );
// get the two last nodes
eNode1 = Dec_IntToEdge( Vec_IntPop(vEdges) );
eNode2 = Dec_IntToEdge( Vec_IntPop(vEdges) );
pNode1 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode1.Node )->pFunc;
pNode2 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode2.Node )->pFunc;
pNode1 = !pNode1? NULL : Abc_ObjNotCond( pNode1, eNode1.fCompl );
pNode2 = !pNode2? NULL : Abc_ObjNotCond( pNode2, eNode2.fCompl );
// check if the new node exists
Type = 0;
pNode3 = NULL;
if ( pNode1 && pNode2 )
pNode3 = Abc_AigXorLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, pNode1, pNode2, &Type );
// create the new node
eNode3 = Dec_GraphAddNodeXor( pGraph, eNode1, eNode2, Type ); // should have the same structure as in AIG
// set level
Level1 = Dec_GraphNode( pGraph, eNode1.Node )->Level;
Level2 = Dec_GraphNode( pGraph, eNode2.Node )->Level;
Dec_GraphNode( pGraph, eNode3.Node )->Level = 2 + Abc_MaxInt(Level1, Level2);
// get the new node if possible
if ( pNode3 )
{
Dec_GraphNode( pGraph, eNode3.Node )->pFunc = Abc_ObjNotCond(pNode3, eNode3.fCompl);
Level3 = Dec_GraphNode( pGraph, eNode3.Node )->Level;
assert( Required == ABC_INFINITY || Level3 == (int)Abc_ObjRegular(pNode3)->Level );
}
if ( !pNode3 || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pNode3)) )
{
(*pnNodesAdded)++;
if ( !pNode1 || !pNode2 )
(*pnNodesAdded) += 2;
else if ( Type == 0 )
{
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, pNode1, Abc_ObjNot(pNode2) );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, Abc_ObjNot(pNode1), pNode2 );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
}
else
{
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, Abc_ObjNot(pNode1), Abc_ObjNot(pNode2) );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, pNode1, pNode2 );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
}
if ( *pnNodesAdded > nNodesSaved )
{
Vec_IntFree( vEdges );
return eQuit;
}
}
// add the resulting node to the form
Abc_NodeEdgeDsdPushOrdered( pGraph, vEdges, Dec_EdgeToInt(eNode3) );
}
// get the last node
eResult = Dec_IntToEdge( Vec_IntPop(vEdges) );
Vec_IntFree( vEdges );
// complement the graph if the node is complemented
eResult.fCompl ^= fCompl;
return eResult;
}
if ( DecType == DSD_NODE_PRIME )
{
DdNode * bLocal, * bVar, * bCofT, * bCofE;
bLocal = Dsd_TreeGetPrimeFunction( pManRst->dd, pNodeDsd ); Cudd_Ref( bLocal );
//Extra_bddPrint( pManRst->dd, bLocal );
bVar = pManRst->dd->vars[0];
bCofE = Cudd_Cofactor( pManRst->dd, bLocal, Cudd_Not(bVar) ); Cudd_Ref( bCofE );
bCofT = Cudd_Cofactor( pManRst->dd, bLocal, bVar ); Cudd_Ref( bCofT );
if ( !Extra_bddIsVar(bCofE) || !Extra_bddIsVar(bCofT) )
{
Cudd_RecursiveDeref( pManRst->dd, bCofE );
Cudd_RecursiveDeref( pManRst->dd, bCofT );
bVar = pManRst->dd->vars[1];
bCofE = Cudd_Cofactor( pManRst->dd, bLocal, Cudd_Not(bVar) ); Cudd_Ref( bCofE );
bCofT = Cudd_Cofactor( pManRst->dd, bLocal, bVar ); Cudd_Ref( bCofT );
if ( !Extra_bddIsVar(bCofE) || !Extra_bddIsVar(bCofT) )
{
Cudd_RecursiveDeref( pManRst->dd, bCofE );
Cudd_RecursiveDeref( pManRst->dd, bCofT );
bVar = pManRst->dd->vars[2];
bCofE = Cudd_Cofactor( pManRst->dd, bLocal, Cudd_Not(bVar) ); Cudd_Ref( bCofE );
bCofT = Cudd_Cofactor( pManRst->dd, bLocal, bVar ); Cudd_Ref( bCofT );
if ( !Extra_bddIsVar(bCofE) || !Extra_bddIsVar(bCofT) )
{
Cudd_RecursiveDeref( pManRst->dd, bCofE );
Cudd_RecursiveDeref( pManRst->dd, bCofT );
Cudd_RecursiveDeref( pManRst->dd, bLocal );
Vec_IntFree( vEdges );
return eQuit;
}
}
}
Cudd_RecursiveDeref( pManRst->dd, bLocal );
// we found the control variable (bVar) and the var-cofactors (bCofT, bCofE)
// find the graph nodes
eNode1 = Dec_IntToEdge( Vec_IntEntry(vEdges, bVar->index) );
eNode2 = Dec_IntToEdge( Vec_IntEntry(vEdges, Cudd_Regular(bCofT)->index) );
eNode3 = Dec_IntToEdge( Vec_IntEntry(vEdges, Cudd_Regular(bCofE)->index) );
// add the complements to the graph nodes
eNode2.fCompl ^= Cudd_IsComplement(bCofT);
eNode3.fCompl ^= Cudd_IsComplement(bCofE);
// because the cofactors are vars, we can just as well deref them here
Cudd_RecursiveDeref( pManRst->dd, bCofE );
Cudd_RecursiveDeref( pManRst->dd, bCofT );
// find the ABC nodes
pNode1 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode1.Node )->pFunc;
pNode2 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode2.Node )->pFunc;
pNode3 = (Abc_Obj_t *)Dec_GraphNode( pGraph, eNode3.Node )->pFunc;
pNode1 = !pNode1? NULL : Abc_ObjNotCond( pNode1, eNode1.fCompl );
pNode2 = !pNode2? NULL : Abc_ObjNotCond( pNode2, eNode2.fCompl );
pNode3 = !pNode3? NULL : Abc_ObjNotCond( pNode3, eNode3.fCompl );
// check if the new node exists
Type = 0;
pNode4 = NULL;
if ( pNode1 && pNode2 && pNode3 )
pNode4 = Abc_AigMuxLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, pNode1, pNode2, pNode3, &Type );
// create the new node
eResult = Dec_GraphAddNodeMux( pGraph, eNode1, eNode2, eNode3, Type ); // should have the same structure as AIG
// set level
Level1 = Dec_GraphNode( pGraph, eNode1.Node )->Level;
Level2 = Dec_GraphNode( pGraph, eNode2.Node )->Level;
Level3 = Dec_GraphNode( pGraph, eNode3.Node )->Level;
Dec_GraphNode( pGraph, eResult.Node )->Level = 2 + Abc_MaxInt( Abc_MaxInt(Level1, Level2), Level3 );
// get the new node if possible
if ( pNode4 )
{
Dec_GraphNode( pGraph, eResult.Node )->pFunc = Abc_ObjNotCond(pNode4, eResult.fCompl);
Level4 = Dec_GraphNode( pGraph, eResult.Node )->Level;
assert( Required == ABC_INFINITY || Level4 == (int)Abc_ObjRegular(pNode4)->Level );
}
if ( !pNode4 || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pNode4)) )
{
(*pnNodesAdded)++;
if ( Type == 0 )
{
if ( !pNode1 || !pNode2 )
(*pnNodesAdded)++;
else
{
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, pNode1, pNode2 );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
}
if ( !pNode1 || !pNode3 )
(*pnNodesAdded)++;
else
{
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, Abc_ObjNot(pNode1), pNode3 );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
}
}
else
{
if ( !pNode1 || !pNode2 )
(*pnNodesAdded)++;
else
{
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, pNode1, Abc_ObjNot(pNode2) );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
}
if ( !pNode1 || !pNode3 )
(*pnNodesAdded)++;
else
{
pTemp = Abc_AigAndLookup( (Abc_Aig_t *)pManRst->pNtk->pManFunc, Abc_ObjNot(pNode1), Abc_ObjNot(pNode3) );
if ( !pTemp || Abc_NodeIsTravIdCurrent(Abc_ObjRegular(pTemp)) )
(*pnNodesAdded)++;
}
}
if ( *pnNodesAdded > nNodesSaved )
{
Vec_IntFree( vEdges );
return eQuit;
}
}
Vec_IntFree( vEdges );
// complement the graph if the node was complemented
eResult.fCompl ^= fCompl;
return eResult;
}
Vec_IntFree( vEdges );
return eQuit;
}
/**Function*************************************************************
Synopsis [Evaluation one DSD.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeEvaluateDsd( Abc_ManRst_t * pManRst, Dsd_Node_t * pNodeDsd, Abc_Obj_t * pRoot, int Required, int nNodesSaved, int * pnNodesAdded )
{
Dec_Graph_t * pGraph;
Dec_Edge_t gEdge;
Abc_Obj_t * pLeaf;
Dec_Node_t * pNode;
int i;
// create the graph and set the leaves
pGraph = Dec_GraphCreate( Vec_PtrSize(pManRst->vLeaves) );
Dec_GraphForEachLeaf( pGraph, pNode, i )
{
pLeaf = (Abc_Obj_t *)Vec_PtrEntry( pManRst->vLeaves, i );
pNode->pFunc = pLeaf;
pNode->Level = pLeaf->Level;
}
// create the decomposition structure from the DSD
*pnNodesAdded = 0;
gEdge = Abc_NodeEvaluateDsd_rec( pGraph, pManRst, pNodeDsd, Required, nNodesSaved, pnNodesAdded );
if ( gEdge.Node > 1000 ) // infeasible
{
*pnNodesAdded = -1;
Dec_GraphFree( pGraph );
return NULL;
}
// quit if the root node is the same
pLeaf = (Abc_Obj_t *)Dec_GraphNode( pGraph, gEdge.Node )->pFunc;
if ( Abc_ObjRegular(pLeaf) == pRoot )
{
*pnNodesAdded = -1;
Dec_GraphFree( pGraph );
return NULL;
}
Dec_GraphSetRoot( pGraph, gEdge );
return pGraph;
}
/**Function*************************************************************
Synopsis [Starts the cut manager for rewriting.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Cut_Man_t * Abc_NtkStartCutManForRestruct( Abc_Ntk_t * pNtk, int nCutMax, int fDag )
{
static Cut_Params_t Params, * pParams = &Params;
Cut_Man_t * pManCut;
Abc_Obj_t * pObj;
int i;
// start the cut manager
memset( pParams, 0, sizeof(Cut_Params_t) );
pParams->nVarsMax = nCutMax; // the max cut size ("k" of the k-feasible cuts)
pParams->nKeepMax = 250; // the max number of cuts kept at a node
pParams->fTruth = 0; // compute truth tables
pParams->fFilter = 1; // filter dominated cuts
pParams->fSeq = 0; // compute sequential cuts
pParams->fDrop = 0; // drop cuts on the fly
pParams->fDag = fDag; // compute DAG cuts
pParams->fTree = 0; // compute tree cuts
pParams->fVerbose = 0; // the verbosiness flag
pParams->nIdsMax = Abc_NtkObjNumMax( pNtk );
pManCut = Cut_ManStart( pParams );
if ( pParams->fDrop )
Cut_ManSetFanoutCounts( pManCut, Abc_NtkFanoutCounts(pNtk) );
// set cuts for PIs
Abc_NtkForEachCi( pNtk, pObj, i )
if ( Abc_ObjFanoutNum(pObj) > 0 )
Cut_NodeSetTriv( pManCut, pObj->Id );
return pManCut;
}
/**Function*************************************************************
Synopsis [Starts the resynthesis manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_ManRst_t * Abc_NtkManRstStart( int nCutMax, int fUpdateLevel, int fUseZeros, int fVerbose )
{
Abc_ManRst_t * p;
p = ABC_ALLOC( Abc_ManRst_t, 1 );
memset( p, 0, sizeof(Abc_ManRst_t) );
// set the parameters
p->nCutMax = nCutMax;
p->fUpdateLevel = fUpdateLevel;
p->fUseZeros = fUseZeros;
p->fVerbose = fVerbose;
// start the BDD manager
p->dd = Cudd_Init( p->nCutMax, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
Cudd_zddVarsFromBddVars( p->dd, 2 );
// start the DSD manager
p->pManDsd = Dsd_ManagerStart( p->dd, p->dd->size, 0 );
// other temp datastructures
p->vVisited = Vec_PtrAlloc( 100 );
p->vLeaves = Vec_PtrAlloc( 100 );
p->vDecs = Vec_PtrAlloc( 100 );
p->vTemp = Vec_PtrAlloc( 100 );
p->vSims = Vec_IntAlloc( 100 );
p->vOnes = Vec_IntAlloc( 100 );
p->vBinate = Vec_IntAlloc( 100 );
p->vTwos = Vec_IntAlloc( 100 );
p->vRands = Vec_IntAlloc( 20 );
{
int i;
for ( i = 0; i < 20; i++ )
Vec_IntPush( p->vRands, (int)RST_RANDOM_UNSIGNED );
}
return p;
}
/**Function*************************************************************
Synopsis [Stops the resynthesis manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkManRstStop( Abc_ManRst_t * p )
{
Dsd_ManagerStop( p->pManDsd );
Extra_StopManager( p->dd );
Vec_PtrFree( p->vDecs );
Vec_PtrFree( p->vLeaves );
Vec_PtrFree( p->vVisited );
Vec_PtrFree( p->vTemp );
Vec_IntFree( p->vSims );
Vec_IntFree( p->vOnes );
Vec_IntFree( p->vBinate );
Vec_IntFree( p->vTwos );
Vec_IntFree( p->vRands );
ABC_FREE( p );
}
/**Function*************************************************************
Synopsis [Stops the resynthesis manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkManRstPrintStats( Abc_ManRst_t * p )
{
printf( "Refactoring statistics:\n" );
printf( "Nodes considered = %8d.\n", p->nNodesConsidered );
printf( "Cuts considered = %8d.\n", p->nCutsConsidered );
printf( "Cuts explored = %8d.\n", p->nCutsExplored );
printf( "Nodes restructured = %8d.\n", p->nNodesRestructured );
printf( "Calculated gain = %8d.\n", p->nNodesGained );
ABC_PRT( "Cuts ", p->timeCut );
ABC_PRT( "Resynthesis", p->timeRes );
ABC_PRT( " BDD ", p->timeBdd );
ABC_PRT( " DSD ", p->timeDsd );
ABC_PRT( " Eval ", p->timeEval );
ABC_PRT( "AIG update ", p->timeNtk );
ABC_PRT( "TOTAL ", p->timeTotal );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_Abc_NodeResubCollectDivs( Abc_ManRst_t * p, Abc_Obj_t * pRoot, Cut_Cut_t * pCut )
{
Abc_Obj_t * pNode, * pFanout;
int i, k;
// collect the leaves of the cut
Vec_PtrClear( p->vDecs );
Abc_NtkIncrementTravId( pRoot->pNtk );
for ( i = 0; i < (int)pCut->nLeaves; i++ )
{
pNode = Abc_NtkObj(pRoot->pNtk, pCut->pLeaves[i]);
if ( pNode == NULL ) // the so-called "bad cut phenomenon" is due to removed nodes
return 0;
Vec_PtrPush( p->vDecs, pNode );
Abc_NodeSetTravIdCurrent( pNode );
}
// explore the fanouts
Vec_PtrForEachEntry( Abc_Obj_t *, p->vDecs, pNode, i )
{
// if the fanout has both fanins in the set, add it
Abc_ObjForEachFanout( pNode, pFanout, k )
{
if ( Abc_NodeIsTravIdCurrent(pFanout) || Abc_ObjIsPo(pFanout) )
continue;
if ( Abc_NodeIsTravIdCurrent(Abc_ObjFanin0(pFanout)) && Abc_NodeIsTravIdCurrent(Abc_ObjFanin1(pFanout)) )
{
Vec_PtrPush( p->vDecs, pFanout );
Abc_NodeSetTravIdCurrent( pFanout );
}
}
}
return 1;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NodeResubMffc_rec( Abc_Obj_t * pNode )
{
if ( Abc_NodeIsTravIdCurrent(pNode) )
return 0;
Abc_NodeSetTravIdCurrent( pNode );
return 1 + Abc_NodeResubMffc_rec( Abc_ObjFanin0(pNode) ) +
Abc_NodeResubMffc_rec( Abc_ObjFanin1(pNode) );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NodeResubMffc( Abc_ManRst_t * p, Vec_Ptr_t * vDecs, int nLeaves, Abc_Obj_t * pRoot )
{
Abc_Obj_t * pObj;
int Counter, i, k;
// increment the traversal ID for the leaves
Abc_NtkIncrementTravId( pRoot->pNtk );
// label the leaves
Vec_PtrForEachEntryStop( Abc_Obj_t *, vDecs, pObj, i, nLeaves )
Abc_NodeSetTravIdCurrent( pObj );
// make sure the node is in the cone and is no one of the leaves
assert( Abc_NodeIsTravIdPrevious(pRoot) );
Counter = Abc_NodeResubMffc_rec( pRoot );
// move the labeled nodes to the end
Vec_PtrClear( p->vTemp );
k = 0;
Vec_PtrForEachEntryStart( Abc_Obj_t *, vDecs, pObj, i, nLeaves )
if ( Abc_NodeIsTravIdCurrent(pObj) )
Vec_PtrPush( p->vTemp, pObj );
else
Vec_PtrWriteEntry( vDecs, k++, pObj );
// add the labeled nodes
Vec_PtrForEachEntry( Abc_Obj_t *, p->vTemp, pObj, i )
Vec_PtrWriteEntry( vDecs, k++, pObj );
assert( k == Vec_PtrSize(p->vDecs) );
assert( pRoot == Vec_PtrEntryLast(p->vDecs) );
return Counter;
}
/**Function*************************************************************
Synopsis [Performs simulation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NodeMffcSimulate( Vec_Ptr_t * vDecs, int nLeaves, Vec_Int_t * vRands, Vec_Int_t * vSims )
{
Abc_Obj_t * pObj;
unsigned uData0, uData1, uData;
int i;
// initialize random simulation data
Vec_IntClear( vSims );
Vec_PtrForEachEntryStop( Abc_Obj_t *, vDecs, pObj, i, nLeaves )
{
uData = (unsigned)Vec_IntEntry( vRands, i );
pObj->pData = (void *)(ABC_PTRUINT_T)uData;
Vec_IntPush( vSims, uData );
}
// simulate
Vec_PtrForEachEntryStart( Abc_Obj_t *, vDecs, pObj, i, nLeaves )
{
uData0 = (unsigned)(ABC_PTRUINT_T)Abc_ObjFanin0(pObj)->pData;
uData1 = (unsigned)(ABC_PTRUINT_T)Abc_ObjFanin1(pObj)->pData;
uData = (Abc_ObjFaninC0(pObj)? ~uData0 : uData0) & (Abc_ObjFaninC1(pObj)? ~uData1 : uData1);
pObj->pData = (void *)(ABC_PTRUINT_T)uData;
Vec_IntPush( vSims, uData );
}
}
/**Function*************************************************************
Synopsis [Full equality check.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NodeCheckFull( Abc_ManRst_t * p, Dec_Graph_t * pGraph )
{
return 1;
}
/**Function*************************************************************
Synopsis [Detect contants.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeMffcConstants( Abc_ManRst_t * p, Vec_Int_t * vSims )
{
Dec_Graph_t * pGraph = NULL;
unsigned uRoot;
// get the root node
uRoot = (unsigned)Vec_IntEntryLast( vSims );
// get the graph if the node looks constant
if ( uRoot == 0 )
pGraph = Dec_GraphCreateConst0();
else if ( uRoot == ~(unsigned)0 )
pGraph = Dec_GraphCreateConst1();
// check the graph
assert(pGraph);
if ( Abc_NodeCheckFull( p, pGraph ) )
return pGraph;
Dec_GraphFree( pGraph );
return NULL;
}
/**Function*************************************************************
Synopsis [Detect single non-overlaps.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeMffcSingleVar( Abc_ManRst_t * p, Vec_Int_t * vSims, int nNodes, Vec_Int_t * vOnes )
{
Dec_Graph_t * pGraph;
unsigned uRoot, uNode;
int i;
Vec_IntClear( vOnes );
Vec_IntClear( p->vBinate );
uRoot = (unsigned)Vec_IntEntryLast( vSims );
for ( i = 0; i < nNodes; i++ )
{
uNode = (unsigned)Vec_IntEntry( vSims, i );
if ( uRoot == uNode || uRoot == ~uNode )
{
pGraph = Dec_GraphCreate( 1 );
Dec_GraphNode( pGraph, 0 )->pFunc = Vec_PtrEntry( p->vDecs, i );
Dec_GraphSetRoot( pGraph, Dec_IntToEdge( (int)(uRoot == ~uNode) ) );
// check the graph
if ( Abc_NodeCheckFull( p, pGraph ) )
return pGraph;
Dec_GraphFree( pGraph );
}
if ( (uRoot & uNode) == 0 )
Vec_IntPush( vOnes, i << 1 );
else if ( (uRoot & ~uNode) == 0 )
Vec_IntPush( vOnes, (i << 1) + 1 );
else
Vec_IntPush( p->vBinate, i );
}
return NULL;
}
/**Function*************************************************************
Synopsis [Detect single non-overlaps.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeMffcSingleNode( Abc_ManRst_t * p, Vec_Int_t * vSims, int nNodes, Vec_Int_t * vOnes )
{
Dec_Graph_t * pGraph;
Dec_Edge_t eNode0, eNode1, eRoot;
unsigned uRoot;
int i, k;
uRoot = (unsigned)Vec_IntEntryLast( vSims );
for ( i = 0; i < vOnes->nSize; i++ )
for ( k = i+1; k < vOnes->nSize; k++ )
if ( ~uRoot == ((unsigned)vOnes->pArray[i] | (unsigned)vOnes->pArray[k]) )
{
eNode0 = Dec_IntToEdge( vOnes->pArray[i] ^ 1 );
eNode1 = Dec_IntToEdge( vOnes->pArray[k] ^ 1 );
pGraph = Dec_GraphCreate( 2 );
Dec_GraphNode( pGraph, 0 )->pFunc = Vec_PtrEntry( p->vDecs, eNode0.Node );
Dec_GraphNode( pGraph, 1 )->pFunc = Vec_PtrEntry( p->vDecs, eNode1.Node );
eRoot = Dec_GraphAddNodeAnd( pGraph, eNode0, eNode1 );
Dec_GraphSetRoot( pGraph, eRoot );
if ( Abc_NodeCheckFull( p, pGraph ) )
return pGraph;
Dec_GraphFree( pGraph );
}
return NULL;
}
/**Function*************************************************************
Synopsis [Detect single non-overlaps.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeMffcDoubleNode( Abc_ManRst_t * p, Vec_Int_t * vSims, int nNodes, Vec_Int_t * vOnes )
{
// Dec_Graph_t * pGraph;
// unsigned uRoot, uNode;
// int i;
return NULL;
}
/**Function*************************************************************
Synopsis [Evaluates resubstution of one cut.]
Description [Returns the graph to add if any.]
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeResubEval( Abc_ManRst_t * p, Abc_Obj_t * pRoot, Cut_Cut_t * pCut )
{
Dec_Graph_t * pGraph;
int nNodesSaved;
// collect the nodes in the cut
if ( !Abc_Abc_NodeResubCollectDivs( p, pRoot, pCut ) )
return NULL;
// label MFFC and count its size
nNodesSaved = Abc_NodeResubMffc( p, p->vDecs, pCut->nLeaves, pRoot );
assert( nNodesSaved > 0 );
// simulate MFFC
Abc_NodeMffcSimulate( p->vDecs, pCut->nLeaves, p->vRands, p->vSims );
// check for constant output
pGraph = Abc_NodeMffcConstants( p, p->vSims );
if ( pGraph )
{
p->nNodesGained += nNodesSaved;
p->nNodesRestructured++;
return pGraph;
}
// check for one literal (fill up the ones array)
pGraph = Abc_NodeMffcSingleVar( p, p->vSims, Vec_IntSize(p->vSims) - nNodesSaved, p->vOnes );
if ( pGraph )
{
p->nNodesGained += nNodesSaved;
p->nNodesRestructured++;
return pGraph;
}
if ( nNodesSaved == 1 )
return NULL;
// look for one node
pGraph = Abc_NodeMffcSingleNode( p, p->vSims, Vec_IntSize(p->vSims) - nNodesSaved, p->vOnes );
if ( pGraph )
{
p->nNodesGained += nNodesSaved - 1;
p->nNodesRestructured++;
return pGraph;
}
if ( nNodesSaved == 2 )
return NULL;
// look for two nodes
pGraph = Abc_NodeMffcDoubleNode( p, p->vSims, Vec_IntSize(p->vSims) - nNodesSaved, p->vOnes );
if ( pGraph )
{
p->nNodesGained += nNodesSaved - 2;
p->nNodesRestructured++;
return pGraph;
}
if ( nNodesSaved == 3 )
return NULL;
/*
// look for MUX/EXOR
pGraph = Abc_NodeMffcMuxNode( p, p->vSims, Vec_IntSize(p->vSims) - nNodesSaved );
if ( pGraph )
{
p->nNodesGained += nNodesSaved - 1;
p->nNodesRestructured++;
return pGraph;
}
*/
return NULL;
}
/**Function*************************************************************
Synopsis [Performs resubstution.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dec_Graph_t * Abc_NodeResubstitute( Abc_ManRst_t * p, Abc_Obj_t * pNode, Cut_Cut_t * pCutList )
{
Dec_Graph_t * pGraph, * pGraphBest = NULL;
Cut_Cut_t * pCut;
int nCuts;
p->nNodesConsidered++;
// count the number of cuts with four inputs or more
nCuts = 0;
for ( pCut = pCutList; pCut; pCut = pCut->pNext )
nCuts += (int)(pCut->nLeaves > 3);
printf( "-----------------------------------\n" );
printf( "Node %6d : Factor-cuts = %5d.\n", pNode->Id, nCuts );
// go through the interesting cuts
for ( pCut = pCutList; pCut; pCut = pCut->pNext )
{
if ( pCut->nLeaves < 4 )
continue;
pGraph = Abc_NodeResubEval( p, pNode, pCut );
if ( pGraph == NULL )
continue;
if ( !pGraphBest || Dec_GraphNodeNum(pGraph) < Dec_GraphNodeNum(pGraphBest) )
{
if ( pGraphBest )
Dec_GraphFree(pGraphBest);
pGraphBest = pGraph;
}
else
Dec_GraphFree(pGraph);
}
return pGraphBest;
}
#else
int Abc_NtkRestructure( Abc_Ntk_t * pNtk, int nCutMax, int fUpdateLevel, int fUseZeros, int fVerbose ) { return 1; }
#endif
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END