| /**CFile**************************************************************** |
| |
| FileName [dchClass.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Choice computation for tech-mapping.] |
| |
| Synopsis [Representation of candidate equivalence classes.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 29, 2008.] |
| |
| Revision [$Id: dchClass.c,v 1.00 2008/07/29 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "dchInt.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| /* |
| The candidate equivalence classes are stored as a vector of pointers |
| to the array of pointers to the nodes in each class. |
| The first node of the class is its representative node. |
| The representative has the smallest topological order among the class nodes. |
| The nodes inside each class are ordered according to their topological order. |
| The classes are ordered according to the topo order of their representatives. |
| */ |
| |
| // internal representation of candidate equivalence classes |
| struct Dch_Cla_t_ |
| { |
| // class information |
| Aig_Man_t * pAig; // original AIG manager |
| Aig_Obj_t *** pId2Class; // non-const classes by ID of repr node |
| int * pClassSizes; // sizes of each equivalence class |
| // statistics |
| int nClasses; // the total number of non-const classes |
| int nCands1; // the total number of const candidates |
| int nLits; // the number of literals in all classes |
| // memory |
| Aig_Obj_t ** pMemClasses; // memory allocated for equivalence classes |
| Aig_Obj_t ** pMemClassesFree; // memory allocated for equivalence classes to be used |
| // temporary data |
| Vec_Ptr_t * vClassOld; // old equivalence class after splitting |
| Vec_Ptr_t * vClassNew; // new equivalence class(es) after splitting |
| // procedures used for class refinement |
| void * pManData; |
| unsigned (*pFuncNodeHash) (void *,Aig_Obj_t *); // returns hash key of the node |
| int (*pFuncNodeIsConst) (void *,Aig_Obj_t *); // returns 1 if the node is a constant |
| int (*pFuncNodesAreEqual) (void *,Aig_Obj_t *, Aig_Obj_t *); // returns 1 if nodes are equal up to a complement |
| }; |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| static inline Aig_Obj_t * Dch_ObjNext( Aig_Obj_t ** ppNexts, Aig_Obj_t * pObj ) { return ppNexts[pObj->Id]; } |
| static inline void Dch_ObjSetNext( Aig_Obj_t ** ppNexts, Aig_Obj_t * pObj, Aig_Obj_t * pNext ) { ppNexts[pObj->Id] = pNext; } |
| |
| // iterator through the equivalence classes |
| #define Dch_ManForEachClass( p, ppClass, i ) \ |
| for ( i = 0; i < Aig_ManObjNumMax(p->pAig); i++ ) \ |
| if ( ((ppClass) = p->pId2Class[i]) == NULL ) {} else |
| // iterator through the nodes in one class |
| #define Dch_ClassForEachNode( p, pRepr, pNode, i ) \ |
| for ( i = 0; i < p->pClassSizes[pRepr->Id]; i++ ) \ |
| if ( ((pNode) = p->pId2Class[pRepr->Id][i]) == NULL ) {} else |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates one equivalence class.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Dch_ObjAddClass( Dch_Cla_t * p, Aig_Obj_t * pRepr, Aig_Obj_t ** pClass, int nSize ) |
| { |
| assert( p->pId2Class[pRepr->Id] == NULL ); |
| p->pId2Class[pRepr->Id] = pClass; |
| assert( p->pClassSizes[pRepr->Id] == 0 ); |
| assert( nSize > 1 ); |
| p->pClassSizes[pRepr->Id] = nSize; |
| p->nClasses++; |
| p->nLits += nSize - 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Removes one equivalence class.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline Aig_Obj_t ** Dch_ObjRemoveClass( Dch_Cla_t * p, Aig_Obj_t * pRepr ) |
| { |
| Aig_Obj_t ** pClass = p->pId2Class[pRepr->Id]; |
| int nSize; |
| assert( pClass != NULL ); |
| p->pId2Class[pRepr->Id] = NULL; |
| nSize = p->pClassSizes[pRepr->Id]; |
| assert( nSize > 1 ); |
| p->nClasses--; |
| p->nLits -= nSize - 1; |
| p->pClassSizes[pRepr->Id] = 0; |
| return pClass; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts representation of equivalence classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Dch_Cla_t * Dch_ClassesStart( Aig_Man_t * pAig ) |
| { |
| Dch_Cla_t * p; |
| p = ABC_ALLOC( Dch_Cla_t, 1 ); |
| memset( p, 0, sizeof(Dch_Cla_t) ); |
| p->pAig = pAig; |
| p->pId2Class = ABC_CALLOC( Aig_Obj_t **, Aig_ManObjNumMax(pAig) ); |
| p->pClassSizes = ABC_CALLOC( int, Aig_ManObjNumMax(pAig) ); |
| p->vClassOld = Vec_PtrAlloc( 100 ); |
| p->vClassNew = Vec_PtrAlloc( 100 ); |
| assert( pAig->pReprs == NULL ); |
| Aig_ManReprStart( pAig, Aig_ManObjNumMax(pAig) ); |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts representation of equivalence classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesSetData( Dch_Cla_t * p, void * pManData, |
| unsigned (*pFuncNodeHash)(void *,Aig_Obj_t *), // returns hash key of the node |
| int (*pFuncNodeIsConst)(void *,Aig_Obj_t *), // returns 1 if the node is a constant |
| int (*pFuncNodesAreEqual)(void *,Aig_Obj_t *, Aig_Obj_t *) ) // returns 1 if nodes are equal up to a complement |
| { |
| p->pManData = pManData; |
| p->pFuncNodeHash = pFuncNodeHash; |
| p->pFuncNodeIsConst = pFuncNodeIsConst; |
| p->pFuncNodesAreEqual = pFuncNodesAreEqual; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stop representation of equivalence classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesStop( Dch_Cla_t * p ) |
| { |
| if ( p->vClassNew ) Vec_PtrFree( p->vClassNew ); |
| if ( p->vClassOld ) Vec_PtrFree( p->vClassOld ); |
| ABC_FREE( p->pId2Class ); |
| ABC_FREE( p->pClassSizes ); |
| ABC_FREE( p->pMemClasses ); |
| ABC_FREE( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stop representation of equivalence classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Dch_ClassesLitNum( Dch_Cla_t * p ) |
| { |
| return p->nLits; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stop representation of equivalence classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Obj_t ** Dch_ClassesReadClass( Dch_Cla_t * p, Aig_Obj_t * pRepr, int * pnSize ) |
| { |
| assert( p->pId2Class[pRepr->Id] != NULL ); |
| assert( p->pClassSizes[pRepr->Id] > 1 ); |
| *pnSize = p->pClassSizes[pRepr->Id]; |
| return p->pId2Class[pRepr->Id]; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks candidate equivalence classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesCheck( Dch_Cla_t * p ) |
| { |
| Aig_Obj_t * pObj, * pPrev, ** ppClass; |
| int i, k, nLits, nClasses, nCands1; |
| nClasses = nLits = 0; |
| Dch_ManForEachClass( p, ppClass, k ) |
| { |
| pPrev = NULL; |
| Dch_ClassForEachNode( p, ppClass[0], pObj, i ) |
| { |
| if ( i == 0 ) |
| assert( Aig_ObjRepr(p->pAig, pObj) == NULL ); |
| else |
| { |
| assert( Aig_ObjRepr(p->pAig, pObj) == ppClass[0] ); |
| assert( pPrev->Id < pObj->Id ); |
| nLits++; |
| } |
| pPrev = pObj; |
| } |
| nClasses++; |
| } |
| nCands1 = 0; |
| Aig_ManForEachObj( p->pAig, pObj, i ) |
| nCands1 += Dch_ObjIsConst1Cand( p->pAig, pObj ); |
| assert( p->nLits == nLits ); |
| assert( p->nCands1 == nCands1 ); |
| assert( p->nClasses == nClasses ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints simulation classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesPrintOne( Dch_Cla_t * p, Aig_Obj_t * pRepr ) |
| { |
| Aig_Obj_t * pObj; |
| int i; |
| Abc_Print( 1, "{ " ); |
| Dch_ClassForEachNode( p, pRepr, pObj, i ) |
| Abc_Print( 1, "%d(%d,%d) ", pObj->Id, pObj->Level, Aig_SupportSize(p->pAig,pObj) ); |
| Abc_Print( 1, "}\n" ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints simulation classes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesPrint( Dch_Cla_t * p, int fVeryVerbose ) |
| { |
| Aig_Obj_t ** ppClass; |
| Aig_Obj_t * pObj; |
| int i; |
| Abc_Print( 1, "Equivalence classes: Const1 = %5d. Class = %5d. Lit = %5d.\n", |
| p->nCands1, p->nClasses, p->nLits ); |
| if ( !fVeryVerbose ) |
| return; |
| Abc_Print( 1, "Constants { " ); |
| Aig_ManForEachObj( p->pAig, pObj, i ) |
| if ( Dch_ObjIsConst1Cand( p->pAig, pObj ) ) |
| Abc_Print( 1, "%d(%d,%d) ", pObj->Id, pObj->Level, Aig_SupportSize(p->pAig,pObj) ); |
| Abc_Print( 1, "}\n" ); |
| Dch_ManForEachClass( p, ppClass, i ) |
| { |
| Abc_Print( 1, "%3d (%3d) : ", i, p->pClassSizes[i] ); |
| Dch_ClassesPrintOne( p, ppClass[0] ); |
| } |
| Abc_Print( 1, "\n" ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates initial simulation classes.] |
| |
| Description [Assumes that simulation info is assigned.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesPrepare( Dch_Cla_t * p, int fLatchCorr, int nMaxLevs ) |
| { |
| Aig_Obj_t ** ppTable, ** ppNexts, ** ppClassNew; |
| Aig_Obj_t * pObj, * pTemp, * pRepr; |
| int i, k, nTableSize, nNodes, iEntry, nEntries, nEntries2; |
| |
| // allocate the hash table hashing simulation info into nodes |
| nTableSize = Abc_PrimeCudd( Aig_ManObjNumMax(p->pAig)/4 ); |
| ppTable = ABC_CALLOC( Aig_Obj_t *, nTableSize ); |
| ppNexts = ABC_CALLOC( Aig_Obj_t *, Aig_ManObjNumMax(p->pAig) ); |
| |
| // add all the nodes to the hash table |
| nEntries = 0; |
| Aig_ManForEachObj( p->pAig, pObj, i ) |
| { |
| if ( fLatchCorr ) |
| { |
| if ( !Aig_ObjIsCi(pObj) ) |
| continue; |
| } |
| else |
| { |
| if ( !Aig_ObjIsNode(pObj) && !Aig_ObjIsCi(pObj) ) |
| continue; |
| // skip the node with more that the given number of levels |
| if ( nMaxLevs && (int)pObj->Level >= nMaxLevs ) |
| continue; |
| } |
| // check if the node belongs to the class of constant 1 |
| if ( p->pFuncNodeIsConst( p->pManData, pObj ) ) |
| { |
| Dch_ObjSetConst1Cand( p->pAig, pObj ); |
| p->nCands1++; |
| continue; |
| } |
| // hash the node by its simulation info |
| iEntry = p->pFuncNodeHash( p->pManData, pObj ) % nTableSize; |
| // add the node to the class |
| if ( ppTable[iEntry] == NULL ) |
| ppTable[iEntry] = pObj; |
| else |
| { |
| // set the representative of this node |
| pRepr = ppTable[iEntry]; |
| Aig_ObjSetRepr( p->pAig, pObj, pRepr ); |
| // add node to the table |
| if ( Dch_ObjNext( ppNexts, pRepr ) == NULL ) |
| { // this will be the second entry |
| p->pClassSizes[pRepr->Id]++; |
| nEntries++; |
| } |
| // add the entry to the list |
| Dch_ObjSetNext( ppNexts, pObj, Dch_ObjNext( ppNexts, pRepr ) ); |
| Dch_ObjSetNext( ppNexts, pRepr, pObj ); |
| p->pClassSizes[pRepr->Id]++; |
| nEntries++; |
| } |
| } |
| |
| // allocate room for classes |
| p->pMemClasses = ABC_ALLOC( Aig_Obj_t *, nEntries + p->nCands1 ); |
| p->pMemClassesFree = p->pMemClasses + nEntries; |
| |
| // copy the entries into storage in the topological order |
| nEntries2 = 0; |
| Aig_ManForEachObj( p->pAig, pObj, i ) |
| { |
| if ( !Aig_ObjIsNode(pObj) && !Aig_ObjIsCi(pObj) ) |
| continue; |
| nNodes = p->pClassSizes[pObj->Id]; |
| // skip the nodes that are not representatives of non-trivial classes |
| if ( nNodes == 0 ) |
| continue; |
| assert( nNodes > 1 ); |
| // add the nodes to the class in the topological order |
| ppClassNew = p->pMemClasses + nEntries2; |
| ppClassNew[0] = pObj; |
| for ( pTemp = Dch_ObjNext(ppNexts, pObj), k = 1; pTemp; |
| pTemp = Dch_ObjNext(ppNexts, pTemp), k++ ) |
| { |
| ppClassNew[nNodes-k] = pTemp; |
| } |
| // add the class of nodes |
| p->pClassSizes[pObj->Id] = 0; |
| Dch_ObjAddClass( p, pObj, ppClassNew, nNodes ); |
| // increment the number of entries |
| nEntries2 += nNodes; |
| } |
| assert( nEntries == nEntries2 ); |
| ABC_FREE( ppTable ); |
| ABC_FREE( ppNexts ); |
| // now it is time to refine the classes |
| Dch_ClassesRefine( p ); |
| Dch_ClassesCheck( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Iteratively refines the classes after simulation.] |
| |
| Description [Returns the number of refinements performed.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Dch_ClassesRefineOneClass( Dch_Cla_t * p, Aig_Obj_t * pReprOld, int fRecursive ) |
| { |
| Aig_Obj_t ** pClassOld, ** pClassNew; |
| Aig_Obj_t * pObj, * pReprNew; |
| int i; |
| |
| // split the class |
| Vec_PtrClear( p->vClassOld ); |
| Vec_PtrClear( p->vClassNew ); |
| Dch_ClassForEachNode( p, pReprOld, pObj, i ) |
| if ( p->pFuncNodesAreEqual(p->pManData, pReprOld, pObj) ) |
| Vec_PtrPush( p->vClassOld, pObj ); |
| else |
| Vec_PtrPush( p->vClassNew, pObj ); |
| // check if splitting happened |
| if ( Vec_PtrSize(p->vClassNew) == 0 ) |
| return 0; |
| |
| // get the new representative |
| pReprNew = (Aig_Obj_t *)Vec_PtrEntry( p->vClassNew, 0 ); |
| assert( Vec_PtrSize(p->vClassOld) > 0 ); |
| assert( Vec_PtrSize(p->vClassNew) > 0 ); |
| |
| // create old class |
| pClassOld = Dch_ObjRemoveClass( p, pReprOld ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassOld, pObj, i ) |
| { |
| pClassOld[i] = pObj; |
| Aig_ObjSetRepr( p->pAig, pObj, i? pReprOld : NULL ); |
| } |
| // create new class |
| pClassNew = pClassOld + i; |
| Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassNew, pObj, i ) |
| { |
| pClassNew[i] = pObj; |
| Aig_ObjSetRepr( p->pAig, pObj, i? pReprNew : NULL ); |
| } |
| |
| // put classes back |
| if ( Vec_PtrSize(p->vClassOld) > 1 ) |
| Dch_ObjAddClass( p, pReprOld, pClassOld, Vec_PtrSize(p->vClassOld) ); |
| if ( Vec_PtrSize(p->vClassNew) > 1 ) |
| Dch_ObjAddClass( p, pReprNew, pClassNew, Vec_PtrSize(p->vClassNew) ); |
| |
| // check if the class should be recursively refined |
| if ( fRecursive && Vec_PtrSize(p->vClassNew) > 1 ) |
| return 1 + Dch_ClassesRefineOneClass( p, pReprNew, 1 ); |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Refines the classes after simulation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Dch_ClassesRefine( Dch_Cla_t * p ) |
| { |
| Aig_Obj_t ** ppClass; |
| int i, nRefis = 0; |
| Dch_ManForEachClass( p, ppClass, i ) |
| nRefis += Dch_ClassesRefineOneClass( p, ppClass[0], 0 ); |
| return nRefis; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns equivalence class of the given node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesCollectOneClass( Dch_Cla_t * p, Aig_Obj_t * pRepr, Vec_Ptr_t * vRoots ) |
| { |
| Aig_Obj_t * pObj; |
| int i; |
| Vec_PtrClear( vRoots ); |
| Dch_ClassForEachNode( p, pRepr, pObj, i ) |
| Vec_PtrPush( vRoots, pObj ); |
| assert( Vec_PtrSize(vRoots) > 1 ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns equivalence class of the given node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Dch_ClassesCollectConst1Group( Dch_Cla_t * p, Aig_Obj_t * pObj, int nNodes, Vec_Ptr_t * vRoots ) |
| { |
| int i, Limit; |
| Vec_PtrClear( vRoots ); |
| Limit = Abc_MinInt( pObj->Id + nNodes, Aig_ManObjNumMax(p->pAig) ); |
| for ( i = pObj->Id; i < Limit; i++ ) |
| { |
| pObj = Aig_ManObj( p->pAig, i ); |
| if ( pObj && Dch_ObjIsConst1Cand( p->pAig, pObj ) ) |
| Vec_PtrPush( vRoots, pObj ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Refine the group of constant 1 nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Dch_ClassesRefineConst1Group( Dch_Cla_t * p, Vec_Ptr_t * vRoots, int fRecursive ) |
| { |
| Aig_Obj_t * pObj, * pReprNew, ** ppClassNew; |
| int i; |
| if ( Vec_PtrSize(vRoots) == 0 ) |
| return 0; |
| // collect the nodes to be refined |
| Vec_PtrClear( p->vClassNew ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vRoots, pObj, i ) |
| if ( !p->pFuncNodeIsConst( p->pManData, pObj ) ) |
| Vec_PtrPush( p->vClassNew, pObj ); |
| // check if there is a new class |
| if ( Vec_PtrSize(p->vClassNew) == 0 ) |
| return 0; |
| p->nCands1 -= Vec_PtrSize(p->vClassNew); |
| pReprNew = (Aig_Obj_t *)Vec_PtrEntry( p->vClassNew, 0 ); |
| Aig_ObjSetRepr( p->pAig, pReprNew, NULL ); |
| if ( Vec_PtrSize(p->vClassNew) == 1 ) |
| return 1; |
| // create a new class composed of these nodes |
| ppClassNew = p->pMemClassesFree; |
| p->pMemClassesFree += Vec_PtrSize(p->vClassNew); |
| Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassNew, pObj, i ) |
| { |
| ppClassNew[i] = pObj; |
| Aig_ObjSetRepr( p->pAig, pObj, i? pReprNew : NULL ); |
| } |
| Dch_ObjAddClass( p, pReprNew, ppClassNew, Vec_PtrSize(p->vClassNew) ); |
| // refine them recursively |
| if ( fRecursive ) |
| return 1 + Dch_ClassesRefineOneClass( p, pReprNew, 1 ); |
| return 1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |