blob: ce60500307f6d459a396b2c1be5430816f9090a2 [file] [log] [blame]
/**CFile****************************************************************
FileName [ivyRwrAlg.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [And-Inverter Graph package.]
Synopsis [Algebraic AIG rewriting.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - May 11, 2006.]
Revision [$Id: ivyRwrAlg.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
***********************************************************************/
#include "ivy.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static int Ivy_ManFindAlgCut( Ivy_Obj_t * pRoot, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone );
static Ivy_Obj_t * Ivy_NodeRewriteAlg( Ivy_Obj_t * pObj, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone, Vec_Ptr_t * vSols, int LevelR, int fUseZeroCost );
static int Ivy_NodeCountMffc( Ivy_Obj_t * pNode );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Algebraic AIG rewriting.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_ManRewriteAlg( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost )
{
Vec_Int_t * vRequired;
Vec_Ptr_t * vFront, * vLeaves, * vCone, * vSol;
Ivy_Obj_t * pObj, * pResult;
int i, RetValue, LevelR, nNodesOld;
int CountUsed, CountUndo;
vRequired = fUpdateLevel? Ivy_ManRequiredLevels( p ) : NULL;
vFront = Vec_PtrAlloc( 100 );
vLeaves = Vec_PtrAlloc( 100 );
vCone = Vec_PtrAlloc( 100 );
vSol = Vec_PtrAlloc( 100 );
// go through the nodes in the topological order
CountUsed = CountUndo = 0;
nNodesOld = Ivy_ManObjIdNext(p);
Ivy_ManForEachObj( p, pObj, i )
{
assert( !Ivy_ObjIsBuf(pObj) );
if ( i >= nNodesOld )
break;
// skip no-nodes and MUX roots
if ( !Ivy_ObjIsNode(pObj) || Ivy_ObjIsExor(pObj) || Ivy_ObjIsMuxType(pObj) )
continue;
// if ( pObj->Id > 297 ) // 296 --- 297
// break;
if ( pObj->Id == 297 )
{
int x = 0;
}
// get the largest algebraic cut
RetValue = Ivy_ManFindAlgCut( pObj, vFront, vLeaves, vCone );
// the case of a trivial tree cut
if ( RetValue == 1 )
continue;
// the case of constant 0 cone
if ( RetValue == -1 )
{
Ivy_ObjReplace( pObj, Ivy_ManConst0(p), 1, 0, 1 );
continue;
}
assert( Vec_PtrSize(vLeaves) > 2 );
// get the required level for this node
LevelR = vRequired? Vec_IntEntry(vRequired, pObj->Id) : 1000000;
// create a new cone
pResult = Ivy_NodeRewriteAlg( pObj, vFront, vLeaves, vCone, vSol, LevelR, fUseZeroCost );
if ( pResult == NULL || pResult == pObj )
continue;
assert( Vec_PtrSize(vSol) == 1 || !Ivy_IsComplement(pResult) );
if ( Ivy_ObjLevel(Ivy_Regular(pResult)) > LevelR && Ivy_ObjRefs(Ivy_Regular(pResult)) == 0 )
Ivy_ObjDelete_rec(Ivy_Regular(pResult), 1), CountUndo++;
else
Ivy_ObjReplace( pObj, pResult, 1, 0, 1 ), CountUsed++;
}
printf( "Used = %d. Undo = %d.\n", CountUsed, CountUndo );
Vec_PtrFree( vFront );
Vec_PtrFree( vCone );
Vec_PtrFree( vSol );
if ( vRequired ) Vec_IntFree( vRequired );
if ( i = Ivy_ManCleanup(p) )
printf( "Cleanup after rewriting removed %d dangling nodes.\n", i );
if ( !Ivy_ManCheck(p) )
printf( "Ivy_ManRewriteAlg(): The check has failed.\n" );
return 1;
}
/**Function*************************************************************
Synopsis [Analizes one node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Ivy_Obj_t * Ivy_NodeRewriteAlg( Ivy_Obj_t * pObj, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone, Vec_Ptr_t * vSols, int LevelR, int fUseZeroCost )
{
int fVerbose = 0;
Ivy_Obj_t * pTemp;
int k, Counter, nMffc, RetValue;
if ( fVerbose )
{
if ( Ivy_ObjIsExor(pObj) )
printf( "x " );
else
printf( " " );
}
/*
printf( "%d ", Vec_PtrSize(vFront) );
printf( "( " );
Vec_PtrForEachEntry( Ivy_Obj_t *, vFront, pTemp, k )
printf( "%d ", Ivy_ObjRefs(Ivy_Regular(pTemp)) );
printf( ")\n" );
*/
// collect nodes in the cone
if ( Ivy_ObjIsExor(pObj) )
Ivy_ManCollectCone( pObj, vFront, vCone );
else
Ivy_ManCollectCone( pObj, vLeaves, vCone );
// deref nodes in the cone
Vec_PtrForEachEntry( Ivy_Obj_t *, vCone, pTemp, k )
{
Ivy_ObjRefsDec( Ivy_ObjFanin0(pTemp) );
Ivy_ObjRefsDec( Ivy_ObjFanin1(pTemp) );
pTemp->fMarkB = 1;
}
// count the MFFC size
Vec_PtrForEachEntry( Ivy_Obj_t *, vFront, pTemp, k )
Ivy_Regular(pTemp)->fMarkA = 1;
nMffc = Ivy_NodeCountMffc( pObj );
Vec_PtrForEachEntry( Ivy_Obj_t *, vFront, pTemp, k )
Ivy_Regular(pTemp)->fMarkA = 0;
if ( fVerbose )
{
Counter = 0;
Vec_PtrForEachEntry( Ivy_Obj_t *, vCone, pTemp, k )
Counter += (Ivy_ObjRefs(pTemp) > 0);
printf( "%5d : Leaves = %2d. Cone = %2d. ConeRef = %2d. Mffc = %d. Lev = %d. LevR = %d.\n",
pObj->Id, Vec_PtrSize(vFront), Vec_PtrSize(vCone), Counter-1, nMffc, Ivy_ObjLevel(pObj), LevelR );
}
/*
printf( "Leaves:" );
Vec_PtrForEachEntry( Ivy_Obj_t *, vLeaves, pTemp, k )
printf( " %d%s", Ivy_Regular(pTemp)->Id, Ivy_IsComplement(pTemp)? "\'" : "" );
printf( "\n" );
printf( "Cone:\n" );
Vec_PtrForEachEntry( Ivy_Obj_t *, vCone, pTemp, k )
printf( " %5d = %d%s %d%s\n", pTemp->Id,
Ivy_ObjFaninId0(pTemp), Ivy_ObjFaninC0(pTemp)? "\'" : "",
Ivy_ObjFaninId1(pTemp), Ivy_ObjFaninC1(pTemp)? "\'" : "" );
*/
RetValue = Ivy_MultiPlus( vLeaves, vCone, Ivy_ObjType(pObj), nMffc + fUseZeroCost, vSols );
// ref nodes in the cone
Vec_PtrForEachEntry( Ivy_Obj_t *, vCone, pTemp, k )
{
Ivy_ObjRefsInc( Ivy_ObjFanin0(pTemp) );
Ivy_ObjRefsInc( Ivy_ObjFanin1(pTemp) );
pTemp->fMarkA = 0;
pTemp->fMarkB = 0;
}
if ( !RetValue )
return NULL;
if ( Vec_PtrSize( vSols ) == 1 )
return Vec_PtrEntry( vSols, 0 );
return Ivy_NodeBalanceBuildSuper( vSols, Ivy_ObjType(pObj), 1 );
}
/**Function*************************************************************
Synopsis [Comparison for node pointers.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_NodeCountMffc_rec( Ivy_Obj_t * pNode )
{
if ( Ivy_ObjRefs(pNode) > 0 || Ivy_ObjIsCi(pNode) || pNode->fMarkA )
return 0;
assert( pNode->fMarkB );
pNode->fMarkA = 1;
// printf( "%d ", pNode->Id );
if ( Ivy_ObjIsBuf(pNode) )
return Ivy_NodeCountMffc_rec( Ivy_ObjFanin0(pNode) );
return 1 + Ivy_NodeCountMffc_rec( Ivy_ObjFanin0(pNode) ) + Ivy_NodeCountMffc_rec( Ivy_ObjFanin1(pNode) );
}
/**Function*************************************************************
Synopsis [Comparison for node pointers.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_NodeCountMffc( Ivy_Obj_t * pNode )
{
assert( pNode->fMarkB );
return 1 + Ivy_NodeCountMffc_rec( Ivy_ObjFanin0(pNode) ) + Ivy_NodeCountMffc_rec( Ivy_ObjFanin1(pNode) );
}
/**Function*************************************************************
Synopsis [Comparison for node pointers.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_ManFindAlgCutCompare( Ivy_Obj_t ** pp1, Ivy_Obj_t ** pp2 )
{
if ( *pp1 < *pp2 )
return -1;
if ( *pp1 > *pp2 )
return 1;
return 0;
}
/**Function*************************************************************
Synopsis [Computing one algebraic cut.]
Description [Returns 1 if the tree-leaves of this node where traversed
and found to have no external references (and have not been collected).
Returns 0 if the tree-leaves have external references and are collected.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_ManFindAlgCut_rec( Ivy_Obj_t * pObj, Ivy_Type_t Type, Vec_Ptr_t * vFront, Vec_Ptr_t * vCone )
{
int RetValue0, RetValue1;
Ivy_Obj_t * pObjR = Ivy_Regular(pObj);
assert( !Ivy_ObjIsBuf(pObjR) );
assert( Type != IVY_EXOR || !Ivy_IsComplement(pObj) );
// make sure the node is not visited twice in different polarities
if ( Ivy_IsComplement(pObj) )
{ // if complemented, mark B
if ( pObjR->fMarkA )
return -1;
pObjR->fMarkB = 1;
}
else
{ // if non-complicated, mark A
if ( pObjR->fMarkB )
return -1;
pObjR->fMarkA = 1;
}
Vec_PtrPush( vCone, pObjR );
// if the node is the end of the tree, return
if ( Ivy_IsComplement(pObj) || Ivy_ObjType(pObj) != Type )
{
if ( Ivy_ObjRefs(pObjR) == 1 )
return 1;
assert( Ivy_ObjRefs(pObjR) > 1 );
Vec_PtrPush( vFront, pObj );
return 0;
}
// branch on the node
assert( !Ivy_IsComplement(pObj) );
assert( Ivy_ObjIsNode(pObj) );
// what if buffer has more than one fanout???
RetValue0 = Ivy_ManFindAlgCut_rec( Ivy_ObjReal( Ivy_ObjChild0(pObj) ), Type, vFront, vCone );
RetValue1 = Ivy_ManFindAlgCut_rec( Ivy_ObjReal( Ivy_ObjChild1(pObj) ), Type, vFront, vCone );
if ( RetValue0 == -1 || RetValue1 == -1 )
return -1;
// the case when both have no external references
if ( RetValue0 && RetValue1 )
{
if ( Ivy_ObjRefs(pObj) == 1 )
return 1;
assert( Ivy_ObjRefs(pObj) > 1 );
Vec_PtrPush( vFront, pObj );
return 0;
}
// the case when one of them has external references
if ( RetValue0 )
Vec_PtrPush( vFront, Ivy_ObjReal( Ivy_ObjChild0(pObj) ) );
if ( RetValue1 )
Vec_PtrPush( vFront, Ivy_ObjReal( Ivy_ObjChild1(pObj) ) );
return 0;
}
/**Function*************************************************************
Synopsis [Computing one algebraic cut.]
Description [Algebraic cut stops when we hit (a) CI, (b) complemented edge,
(c) boundary of different gates. Returns 1 if this is a pure tree.
Returns -1 if the contant 0 is detected. Return 0 if the array can be used.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_ManFindAlgCut( Ivy_Obj_t * pRoot, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone )
{
Ivy_Obj_t * pObj, * pPrev;
int RetValue, i;
assert( !Ivy_IsComplement(pRoot) );
assert( Ivy_ObjIsNode(pRoot) );
// clear the frontier and collect the nodes
Vec_PtrClear( vCone );
Vec_PtrClear( vFront );
Vec_PtrClear( vLeaves );
RetValue = Ivy_ManFindAlgCut_rec( pRoot, Ivy_ObjType(pRoot), vFront, vCone );
// clean the marks
Vec_PtrForEachEntry( Ivy_Obj_t *, vCone, pObj, i )
pObj->fMarkA = pObj->fMarkB = 0;
// quit if the same node is found in both polarities
if ( RetValue == -1 )
return -1;
// return if the node is the root of a tree
if ( RetValue == 1 )
return 1;
// return if the cut is composed of two nodes
if ( Vec_PtrSize(vFront) <= 2 )
return 1;
// sort the entries in increasing order
Vec_PtrSort( vFront, (int (*)(void))Ivy_ManFindAlgCutCompare );
// remove duplicates from vFront and save the nodes in vLeaves
pPrev = Vec_PtrEntry(vFront, 0);
Vec_PtrPush( vLeaves, pPrev );
Vec_PtrForEachEntryStart( Ivy_Obj_t *, vFront, pObj, i, 1 )
{
// compare current entry and the previous entry
if ( pObj == pPrev )
{
if ( Ivy_ObjIsExor(pRoot) ) // A <+> A = 0
{
// vLeaves are no longer structural support of pRoot!!!
Vec_PtrPop(vLeaves);
pPrev = Vec_PtrSize(vLeaves) == 0 ? NULL : Vec_PtrEntryLast(vLeaves);
}
continue;
}
if ( pObj == Ivy_Not(pPrev) )
{
assert( Ivy_ObjIsAnd(pRoot) );
return -1;
}
pPrev = pObj;
Vec_PtrPush( vLeaves, pObj );
}
if ( Vec_PtrSize(vLeaves) == 0 )
return -1;
if ( Vec_PtrSize(vLeaves) <= 2 )
return 1;
return 0;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END