| /**CFile**************************************************************** |
| |
| FileName [ivyCut.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [And-Inverter Graph package.] |
| |
| Synopsis [Computes reconvergence driven sequential cut.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - May 11, 2006.] |
| |
| Revision [$Id: ivyCut.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "ivy.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| static inline int Ivy_NodeCutHashValue( int NodeId ) { return 1 << (NodeId % 31); } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Evaluate the cost of removing the node from the set of leaves.] |
| |
| Description [Returns the number of new leaves that will be brought in. |
| Returns large number if the node cannot be removed from the set of leaves.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Ivy_NodeGetLeafCostOne( Ivy_Man_t * p, int Leaf, Vec_Int_t * vInside ) |
| { |
| Ivy_Obj_t * pNode; |
| int nLatches, FaninLeaf, Cost; |
| // make sure leaf is not a contant node |
| assert( Leaf > 0 ); |
| // get the node |
| pNode = Ivy_ManObj( p, Ivy_LeafId(Leaf) ); |
| // cannot expand over the PI node |
| if ( Ivy_ObjIsPi(pNode) || Ivy_ObjIsConst1(pNode) ) |
| return 999; |
| // get the number of latches |
| nLatches = Ivy_LeafLat(Leaf) + Ivy_ObjIsLatch(pNode); |
| if ( nLatches > 15 ) |
| return 999; |
| // get the first fanin |
| FaninLeaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pNode), nLatches ); |
| Cost = FaninLeaf && (Vec_IntFind(vInside, FaninLeaf) == -1); |
| // quit if this is the one fanin node |
| if ( Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) ) |
| return Cost; |
| assert( Ivy_ObjIsNode(pNode) ); |
| // get the second fanin |
| FaninLeaf = Ivy_LeafCreate( Ivy_ObjFaninId1(pNode), nLatches ); |
| Cost += FaninLeaf && (Vec_IntFind(vInside, FaninLeaf) == -1); |
| return Cost; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Builds reconvergence-driven cut by changing one leaf at a time.] |
| |
| Description [This procedure looks at the current leaves and tries to change |
| one leaf at a time in such a way that the cut grows as little as possible. |
| In evaluating the fanins, this procedure looks only at their immediate |
| predecessors (this is why it is called a one-level construction procedure).] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManSeqFindCut_int( Ivy_Man_t * p, Vec_Int_t * vFront, Vec_Int_t * vInside, int nSizeLimit ) |
| { |
| Ivy_Obj_t * pNode; |
| int CostBest, CostCur, Leaf, LeafBest, Next, nLatches, i; |
| int LeavesBest[10]; |
| int Counter; |
| |
| // add random selection of the best fanin!!! |
| |
| // find the best fanin |
| CostBest = 99; |
| LeafBest = -1; |
| Counter = -1; |
| //printf( "Evaluating fanins of the cut:\n" ); |
| Vec_IntForEachEntry( vFront, Leaf, i ) |
| { |
| CostCur = Ivy_NodeGetLeafCostOne( p, Leaf, vInside ); |
| //printf( " Fanin %s has cost %d.\n", Ivy_ObjName(pNode), CostCur ); |
| if ( CostBest > CostCur ) |
| { |
| CostBest = CostCur; |
| LeafBest = Leaf; |
| LeavesBest[0] = Leaf; |
| Counter = 1; |
| } |
| else if ( CostBest == CostCur ) |
| LeavesBest[Counter++] = Leaf; |
| |
| if ( CostBest <= 1 ) // can be if ( CostBest <= 1 ) |
| break; |
| } |
| if ( CostBest == 99 ) |
| return 0; |
| // return Ivy_NodeBuildCutLevelTwo_int( vInside, vFront, nFaninLimit ); |
| |
| assert( CostBest < 3 ); |
| if ( Vec_IntSize(vFront) - 1 + CostBest > nSizeLimit ) |
| return 0; |
| // return Ivy_NodeBuildCutLevelTwo_int( vInside, vFront, nFaninLimit ); |
| |
| assert( Counter > 0 ); |
| printf( "%d", Counter ); |
| |
| LeafBest = LeavesBest[rand() % Counter]; |
| |
| // remove the node from the array |
| assert( LeafBest >= 0 ); |
| Vec_IntRemove( vFront, LeafBest ); |
| //printf( "Removing fanin %s.\n", Ivy_ObjName(pNode) ); |
| |
| // get the node and its latches |
| pNode = Ivy_ManObj( p, Ivy_LeafId(LeafBest) ); |
| nLatches = Ivy_LeafLat(LeafBest) + Ivy_ObjIsLatch(pNode); |
| assert( Ivy_ObjIsNode(pNode) || Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) ); |
| |
| // add the left child to the fanins |
| Next = Ivy_LeafCreate( Ivy_ObjFaninId0(pNode), nLatches ); |
| if ( Next && Vec_IntFind(vInside, Next) == -1 ) |
| { |
| //printf( "Adding fanin %s.\n", Ivy_ObjName(pNext) ); |
| Vec_IntPush( vFront, Next ); |
| Vec_IntPush( vInside, Next ); |
| } |
| |
| // quit if this is the one fanin node |
| if ( Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) ) |
| return 1; |
| assert( Ivy_ObjIsNode(pNode) ); |
| |
| // add the right child to the fanins |
| Next = Ivy_LeafCreate( Ivy_ObjFaninId1(pNode), nLatches ); |
| if ( Next && Vec_IntFind(vInside, Next) == -1 ) |
| { |
| //printf( "Adding fanin %s.\n", Ivy_ObjName(pNext) ); |
| Vec_IntPush( vFront, Next ); |
| Vec_IntPush( vInside, Next ); |
| } |
| assert( Vec_IntSize(vFront) <= nSizeLimit ); |
| // keep doing this |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes one sequential cut of the given size.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManSeqFindCut( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Int_t * vFront, Vec_Int_t * vInside, int nSize ) |
| { |
| assert( !Ivy_IsComplement(pRoot) ); |
| assert( Ivy_ObjIsNode(pRoot) ); |
| assert( Ivy_ObjFaninId0(pRoot) ); |
| assert( Ivy_ObjFaninId1(pRoot) ); |
| |
| // start the cut |
| Vec_IntClear( vFront ); |
| Vec_IntPush( vFront, Ivy_LeafCreate(Ivy_ObjFaninId0(pRoot), 0) ); |
| Vec_IntPush( vFront, Ivy_LeafCreate(Ivy_ObjFaninId1(pRoot), 0) ); |
| |
| // start the visited nodes |
| Vec_IntClear( vInside ); |
| Vec_IntPush( vInside, Ivy_LeafCreate(pRoot->Id, 0) ); |
| Vec_IntPush( vInside, Ivy_LeafCreate(Ivy_ObjFaninId0(pRoot), 0) ); |
| Vec_IntPush( vInside, Ivy_LeafCreate(Ivy_ObjFaninId1(pRoot), 0) ); |
| |
| // compute the cut |
| while ( Ivy_ManSeqFindCut_int( p, vFront, vInside, nSize ) ); |
| assert( Vec_IntSize(vFront) <= nSize ); |
| } |
| |
| |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computing Boolean cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManFindBoolCut_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vVolume, Ivy_Obj_t * pPivot ) |
| { |
| int RetValue0, RetValue1; |
| if ( pObj == pPivot ) |
| { |
| Vec_PtrPushUnique( vLeaves, pObj ); |
| Vec_PtrPushUnique( vVolume, pObj ); |
| return 1; |
| } |
| if ( pObj->fMarkA ) |
| return 0; |
| |
| // assert( !Ivy_ObjIsCi(pObj) ); |
| if ( Ivy_ObjIsCi(pObj) ) |
| return 0; |
| |
| if ( Ivy_ObjIsBuf(pObj) ) |
| { |
| RetValue0 = Ivy_ManFindBoolCut_rec( p, Ivy_ObjFanin0(pObj), vLeaves, vVolume, pPivot ); |
| if ( !RetValue0 ) |
| return 0; |
| Vec_PtrPushUnique( vVolume, pObj ); |
| return 1; |
| } |
| assert( Ivy_ObjIsNode(pObj) ); |
| RetValue0 = Ivy_ManFindBoolCut_rec( p, Ivy_ObjFanin0(pObj), vLeaves, vVolume, pPivot ); |
| RetValue1 = Ivy_ManFindBoolCut_rec( p, Ivy_ObjFanin1(pObj), vLeaves, vVolume, pPivot ); |
| if ( !RetValue0 && !RetValue1 ) |
| return 0; |
| // add new leaves |
| if ( !RetValue0 ) |
| { |
| Vec_PtrPushUnique( vLeaves, Ivy_ObjFanin0(pObj) ); |
| Vec_PtrPushUnique( vVolume, Ivy_ObjFanin0(pObj) ); |
| } |
| if ( !RetValue1 ) |
| { |
| Vec_PtrPushUnique( vLeaves, Ivy_ObjFanin1(pObj) ); |
| Vec_PtrPushUnique( vVolume, Ivy_ObjFanin1(pObj) ); |
| } |
| Vec_PtrPushUnique( vVolume, pObj ); |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the cost of one node (how many new nodes are added.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManFindBoolCutCost( Ivy_Obj_t * pObj ) |
| { |
| int Cost; |
| // make sure the node is in the construction zone |
| assert( pObj->fMarkA == 1 ); |
| // cannot expand over the PI node |
| if ( Ivy_ObjIsCi(pObj) ) |
| return 999; |
| // always expand over the buffer |
| if ( Ivy_ObjIsBuf(pObj) ) |
| return !Ivy_ObjFanin0(pObj)->fMarkA; |
| // get the cost of the cone |
| Cost = (!Ivy_ObjFanin0(pObj)->fMarkA) + (!Ivy_ObjFanin1(pObj)->fMarkA); |
| // return the number of nodes to be added to the leaves if this node is removed |
| return Cost; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computing Boolean cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_ManFindBoolCut( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Ptr_t * vFront, Vec_Ptr_t * vVolume, Vec_Ptr_t * vLeaves ) |
| { |
| Ivy_Obj_t * pObj = NULL; // Suppress "might be used uninitialized" |
| Ivy_Obj_t * pFaninC, * pFanin0, * pFanin1, * pPivot; |
| int RetValue, LevelLimit, Lev, k; |
| assert( !Ivy_IsComplement(pRoot) ); |
| // clear the frontier and collect the nodes |
| Vec_PtrClear( vFront ); |
| Vec_PtrClear( vVolume ); |
| if ( Ivy_ObjIsMuxType(pRoot) ) |
| pFaninC = Ivy_ObjRecognizeMux( pRoot, &pFanin0, &pFanin1 ); |
| else |
| { |
| pFaninC = NULL; |
| pFanin0 = Ivy_ObjFanin0(pRoot); |
| pFanin1 = Ivy_ObjFanin1(pRoot); |
| } |
| // start cone A |
| pFanin0->fMarkA = 1; |
| Vec_PtrPush( vFront, pFanin0 ); |
| Vec_PtrPush( vVolume, pFanin0 ); |
| // start cone B |
| pFanin1->fMarkB = 1; |
| Vec_PtrPush( vFront, pFanin1 ); |
| Vec_PtrPush( vVolume, pFanin1 ); |
| // iteratively expand until the common node (pPivot) is found or limit is reached |
| assert( Ivy_ObjLevel(pRoot) == Ivy_ObjLevelNew(pRoot) ); |
| pPivot = NULL; |
| LevelLimit = IVY_MAX( Ivy_ObjLevel(pRoot) - 10, 1 ); |
| for ( Lev = Ivy_ObjLevel(pRoot) - 1; Lev >= LevelLimit; Lev-- ) |
| { |
| while ( 1 ) |
| { |
| // find the next node to expand on this level |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vFront, pObj, k ) |
| if ( (int)pObj->Level == Lev ) |
| break; |
| if ( k == Vec_PtrSize(vFront) ) |
| break; |
| assert( (int)pObj->Level <= Lev ); |
| assert( pObj->fMarkA ^ pObj->fMarkB ); |
| // remove the old node |
| Vec_PtrRemove( vFront, pObj ); |
| |
| // expand this node |
| pFanin0 = Ivy_ObjFanin0(pObj); |
| if ( !pFanin0->fMarkA && !pFanin0->fMarkB ) |
| { |
| Vec_PtrPush( vFront, pFanin0 ); |
| Vec_PtrPush( vVolume, pFanin0 ); |
| } |
| // mark the new nodes |
| if ( pObj->fMarkA ) |
| pFanin0->fMarkA = 1; |
| if ( pObj->fMarkB ) |
| pFanin0->fMarkB = 1; |
| |
| if ( Ivy_ObjIsBuf(pObj) ) |
| { |
| if ( pFanin0->fMarkA && pFanin0->fMarkB ) |
| { |
| pPivot = pFanin0; |
| break; |
| } |
| continue; |
| } |
| |
| // expand this node |
| pFanin1 = Ivy_ObjFanin1(pObj); |
| if ( !pFanin1->fMarkA && !pFanin1->fMarkB ) |
| { |
| Vec_PtrPush( vFront, pFanin1 ); |
| Vec_PtrPush( vVolume, pFanin1 ); |
| } |
| // mark the new nodes |
| if ( pObj->fMarkA ) |
| pFanin1->fMarkA = 1; |
| if ( pObj->fMarkB ) |
| pFanin1->fMarkB = 1; |
| |
| // consider if it is time to quit |
| if ( pFanin0->fMarkA && pFanin0->fMarkB ) |
| { |
| pPivot = pFanin0; |
| break; |
| } |
| if ( pFanin1->fMarkA && pFanin1->fMarkB ) |
| { |
| pPivot = pFanin1; |
| break; |
| } |
| } |
| if ( pPivot != NULL ) |
| break; |
| } |
| if ( pPivot == NULL ) |
| return 0; |
| // if the MUX control is defined, it should not be |
| if ( pFaninC && !pFaninC->fMarkA && !pFaninC->fMarkB ) |
| Vec_PtrPush( vFront, pFaninC ); |
| // clean the markings |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vVolume, pObj, k ) |
| pObj->fMarkA = pObj->fMarkB = 0; |
| |
| // mark the nodes on the frontier (including the pivot) |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vFront, pObj, k ) |
| pObj->fMarkA = 1; |
| // cut exists, collect all the nodes on the shortest path to the pivot |
| Vec_PtrClear( vLeaves ); |
| Vec_PtrClear( vVolume ); |
| RetValue = Ivy_ManFindBoolCut_rec( p, pRoot, vLeaves, vVolume, pPivot ); |
| assert( RetValue == 1 ); |
| // unmark the nodes on the frontier (including the pivot) |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vFront, pObj, k ) |
| pObj->fMarkA = 0; |
| |
| // mark the nodes in the volume |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vVolume, pObj, k ) |
| pObj->fMarkA = 1; |
| // expand the cut without increasing its size |
| while ( 1 ) |
| { |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vLeaves, pObj, k ) |
| if ( Ivy_ManFindBoolCutCost(pObj) < 2 ) |
| break; |
| if ( k == Vec_PtrSize(vLeaves) ) |
| break; |
| // the node can be expanded |
| // remove the old node |
| Vec_PtrRemove( vLeaves, pObj ); |
| // expand this node |
| pFanin0 = Ivy_ObjFanin0(pObj); |
| if ( !pFanin0->fMarkA ) |
| { |
| pFanin0->fMarkA = 1; |
| Vec_PtrPush( vVolume, pFanin0 ); |
| Vec_PtrPush( vLeaves, pFanin0 ); |
| } |
| if ( Ivy_ObjIsBuf(pObj) ) |
| continue; |
| // expand this node |
| pFanin1 = Ivy_ObjFanin1(pObj); |
| if ( !pFanin1->fMarkA ) |
| { |
| pFanin1->fMarkA = 1; |
| Vec_PtrPush( vVolume, pFanin1 ); |
| Vec_PtrPush( vLeaves, pFanin1 ); |
| } |
| } |
| // unmark the nodes in the volume |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vVolume, pObj, k ) |
| pObj->fMarkA = 0; |
| return 1; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManTestCutsBool( Ivy_Man_t * p ) |
| { |
| Vec_Ptr_t * vFront, * vVolume, * vLeaves; |
| Ivy_Obj_t * pObj;//, * pTemp; |
| int i, RetValue;//, k; |
| vFront = Vec_PtrAlloc( 100 ); |
| vVolume = Vec_PtrAlloc( 100 ); |
| vLeaves = Vec_PtrAlloc( 100 ); |
| Ivy_ManForEachObj( p, pObj, i ) |
| { |
| if ( !Ivy_ObjIsNode(pObj) ) |
| continue; |
| if ( Ivy_ObjIsMuxType(pObj) ) |
| { |
| printf( "m" ); |
| continue; |
| } |
| if ( Ivy_ObjIsExor(pObj) ) |
| printf( "x" ); |
| RetValue = Ivy_ManFindBoolCut( p, pObj, vFront, vVolume, vLeaves ); |
| if ( RetValue == 0 ) |
| printf( "- " ); |
| else |
| printf( "%d ", Vec_PtrSize(vLeaves) ); |
| /* |
| printf( "( " ); |
| Vec_PtrForEachEntry( Ivy_Obj_t *, vFront, pTemp, k ) |
| printf( "%d ", Ivy_ObjRefs(Ivy_Regular(pTemp)) ); |
| printf( ")\n" ); |
| */ |
| } |
| printf( "\n" ); |
| Vec_PtrFree( vFront ); |
| Vec_PtrFree( vVolume ); |
| Vec_PtrFree( vLeaves ); |
| } |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Find the hash value of the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline unsigned Ivy_NodeCutHash( Ivy_Cut_t * pCut ) |
| { |
| int i; |
| // for ( i = 1; i < pCut->nSize; i++ ) |
| // assert( pCut->pArray[i-1] < pCut->pArray[i] ); |
| pCut->uHash = 0; |
| for ( i = 0; i < pCut->nSize; i++ ) |
| pCut->uHash |= (1 << (pCut->pArray[i] % 31)); |
| return pCut->uHash; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Removes one node to the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Ivy_NodeCutShrink( Ivy_Cut_t * pCut, int iOld ) |
| { |
| int i, k; |
| for ( i = k = 0; i < pCut->nSize; i++ ) |
| if ( pCut->pArray[i] != iOld ) |
| pCut->pArray[k++] = pCut->pArray[i]; |
| assert( k == pCut->nSize - 1 ); |
| pCut->nSize--; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Adds one node to the cut.] |
| |
| Description [Returns 1 if the cuts is still okay.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Ivy_NodeCutExtend( Ivy_Cut_t * pCut, int iNew ) |
| { |
| int i; |
| for ( i = 0; i < pCut->nSize; i++ ) |
| if ( pCut->pArray[i] == iNew ) |
| return 1; |
| // check if there is room |
| if ( pCut->nSize == pCut->nSizeMax ) |
| return 0; |
| // add the new one |
| for ( i = pCut->nSize - 1; i >= 0; i-- ) |
| if ( pCut->pArray[i] > iNew ) |
| pCut->pArray[i+1] = pCut->pArray[i]; |
| else |
| { |
| assert( pCut->pArray[i] < iNew ); |
| break; |
| } |
| pCut->pArray[i+1] = iNew; |
| pCut->nSize++; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if the cut can be constructed; 0 otherwise.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Ivy_NodeCutPrescreen( 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_NodeCutDeriveNew( 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_NodeCutHashValue( IdNew0 ); |
| } |
| IdNew0 = 0x7FFFFFFF; |
| } |
| if ( IdNew1 <= pCut->pArray[i] ) |
| { |
| if ( IdNew1 < pCut->pArray[i] ) |
| { |
| pCutNew->pArray[ k++ ] = IdNew1; |
| uHash |= Ivy_NodeCutHashValue( IdNew1 ); |
| } |
| IdNew1 = 0x7FFFFFFF; |
| } |
| pCutNew->pArray[ k++ ] = pCut->pArray[i]; |
| uHash |= Ivy_NodeCutHashValue( pCut->pArray[i] ); |
| } |
| if ( IdNew0 < 0x7FFFFFFF ) |
| { |
| pCutNew->pArray[ k++ ] = IdNew0; |
| uHash |= Ivy_NodeCutHashValue( IdNew0 ); |
| } |
| if ( IdNew1 < 0x7FFFFFFF ) |
| { |
| pCutNew->pArray[ k++ ] = IdNew1; |
| uHash |= Ivy_NodeCutHashValue( 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 [Check if the cut exists.] |
| |
| Description [Returns 1 if the cut exists.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Ivy_NodeCutFindOrAdd( 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->uHash == pCutNew->uHash && pCut->nSize == pCutNew->nSize ) |
| { |
| for ( k = 0; k < pCutNew->nSize; k++ ) |
| if ( pCut->pArray[k] != pCutNew->pArray[k] ) |
| break; |
| if ( k == pCutNew->nSize ) |
| return 1; |
| } |
| } |
| assert( pCutStore->nCuts < pCutStore->nCutsMax ); |
| // add the cut |
| pCut = pCutStore->pCuts + pCutStore->nCuts++; |
| *pCut = *pCutNew; |
| return 0; |
| } |
| |
| /**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++ ) |
| { |
| 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_NodeCutFindOrAddFilter( 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 |
| // --pCutStore->nCuts; |
| // for ( k = i; k < pCutStore->nCuts; k++ ) |
| // pCutStore->pCuts[k] = pCutStore->pCuts[k+1]; |
| // i--; |
| pCut->nSize = 0; |
| } |
| } |
| assert( pCutStore->nCuts < pCutStore->nCutsMax ); |
| // add the cut |
| pCut = pCutStore->pCuts + pCutStore->nCuts++; |
| *pCut = *pCutNew; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Print the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_NodeCompactCuts( Ivy_Store_t * pCutStore ) |
| { |
| Ivy_Cut_t * pCut; |
| int i, k; |
| for ( i = k = 0; i < pCutStore->nCuts; i++ ) |
| { |
| pCut = pCutStore->pCuts + i; |
| if ( pCut->nSize == 0 ) |
| continue; |
| pCutStore->pCuts[k++] = *pCut; |
| } |
| pCutStore->nCuts = k; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Print the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_NodePrintCut( 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_NodePrintCuts( Ivy_Store_t * pCutStore ) |
| { |
| int i; |
| printf( "Node %d\n", pCutStore->pCuts[0].pArray[0] ); |
| for ( i = 0; i < pCutStore->nCuts; i++ ) |
| Ivy_NodePrintCut( pCutStore->pCuts + i ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline Ivy_Obj_t * Ivy_ObjRealFanin( Ivy_Obj_t * pObj ) |
| { |
| if ( !Ivy_ObjIsBuf(pObj) ) |
| return pObj; |
| return Ivy_ObjRealFanin( Ivy_ObjFanin0(pObj) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Ivy_Store_t * Ivy_NodeFindCutsAll( 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, 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] = pObj->Id; |
| Ivy_NodeCutHash( pCutNew ); |
| // add the trivial cut |
| Ivy_NodeCutFindOrAdd( pCutStore, 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, pCut->pArray[k] ); |
| if ( Ivy_ObjIsCi(pLeaf) ) |
| continue; |
| /* |
| *pCutNew = *pCut; |
| Ivy_NodeCutShrink( pCutNew, pLeaf->Id ); |
| if ( !Ivy_NodeCutExtend( pCutNew, Ivy_ObjFaninId0(pLeaf) ) ) |
| continue; |
| if ( Ivy_ObjIsNode(pLeaf) && !Ivy_NodeCutExtend( pCutNew, Ivy_ObjFaninId1(pLeaf) ) ) |
| continue; |
| Ivy_NodeCutHash( pCutNew ); |
| */ |
| iLeaf0 = Ivy_ObjId( Ivy_ObjRealFanin(Ivy_ObjFanin0(pLeaf)) ); |
| iLeaf1 = Ivy_ObjId( Ivy_ObjRealFanin(Ivy_ObjFanin1(pLeaf)) ); |
| // if ( iLeaf0 == iLeaf1 ) // strange situation observed on Jan 18, 2007 |
| // continue; |
| if ( !Ivy_NodeCutPrescreen( pCut, iLeaf0, iLeaf1 ) ) |
| continue; |
| if ( iLeaf0 > iLeaf1 ) |
| Ivy_NodeCutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf1, iLeaf0 ); |
| else |
| Ivy_NodeCutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf0, iLeaf1 ); |
| Ivy_NodeCutFindOrAddFilter( pCutStore, pCutNew ); |
| if ( pCutStore->nCuts == IVY_CUT_LIMIT ) |
| break; |
| } |
| if ( pCutStore->nCuts == IVY_CUT_LIMIT ) |
| break; |
| } |
| Ivy_NodeCompactCuts( pCutStore ); |
| // Ivy_NodePrintCuts( pCutStore ); |
| return pCutStore; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Ivy_ManTestCutsAll( Ivy_Man_t * p ) |
| { |
| Ivy_Obj_t * pObj; |
| int i, nCutsCut, nCutsTotal, nNodeTotal, nNodeOver; |
| abctime clk = Abc_Clock(); |
| nNodeTotal = nNodeOver = 0; |
| nCutsTotal = -Ivy_ManNodeNum(p); |
| Ivy_ManForEachObj( p, pObj, i ) |
| { |
| if ( !Ivy_ObjIsNode(pObj) ) |
| continue; |
| nCutsCut = Ivy_NodeFindCutsAll( p, pObj, 5 )->nCuts; |
| nCutsTotal += nCutsCut; |
| nNodeOver += (nCutsCut == IVY_CUT_LIMIT); |
| nNodeTotal++; |
| } |
| printf( "Total cuts = %6d. Trivial = %6d. Nodes = %6d. Satur = %6d. ", |
| nCutsTotal, Ivy_ManPiNum(p) + Ivy_ManNodeNum(p), nNodeTotal, nNodeOver ); |
| ABC_PRT( "Time", Abc_Clock() - clk ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |