| /**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 |
| |