/**CFile**************************************************************** FileName [rwrDec.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [DAG-aware AIG rewriting package.] Synopsis [Evaluation and decomposition procedures.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 20, 2005.] Revision [$Id: rwrDec.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] ***********************************************************************/ #include "rwr.h" #include "bool/dec/dec.h" #include "aig/ivy/ivy.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// static Dec_Graph_t * Rwr_CutEvaluate( Rwr_Man_t * p, Abc_Obj_t * pRoot, Cut_Cut_t * pCut, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int LevelMax, int * pGainBest, int fPlaceEnable ); static int Rwr_CutIsBoolean( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ); static int Rwr_CutCountNumNodes( Abc_Obj_t * pObj, Cut_Cut_t * pCut ); static int Rwr_NodeGetDepth_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Performs rewriting for one node.] Description [This procedure considers all the cuts computed for the node and tries to rewrite each of them using the "forest" of different AIG structures precomputed and stored in the RWR manager. Determines the best rewriting and computes the gain in the number of AIG nodes in the final network. In the end, p->vFanins contains information about the best cut that can be used for rewriting, while p->pGraph gives the decomposition dag (represented using decomposition graph data structure). Returns gain in the number of nodes or -1 if node cannot be rewritten.] SideEffects [] SeeAlso [] ***********************************************************************/ int Rwr_NodeRewrite( Rwr_Man_t * p, Cut_Man_t * pManCut, Abc_Obj_t * pNode, int fUpdateLevel, int fUseZeros, int fPlaceEnable ) { int fVeryVerbose = 0; Dec_Graph_t * pGraph; Cut_Cut_t * pCut;//, * pTemp; Abc_Obj_t * pFanin; unsigned uPhase; unsigned uTruthBest = 0; // Suppress "might be used uninitialized" unsigned uTruth; char * pPerm; int Required, nNodesSaved; int nNodesSaveCur = -1; // Suppress "might be used uninitialized" int i, GainCur, GainBest = -1; abctime clk, clk2;//, Counter; p->nNodesConsidered++; // get the required times Required = fUpdateLevel? Abc_ObjRequiredLevel(pNode) : ABC_INFINITY; // get the node's cuts clk = Abc_Clock(); pCut = (Cut_Cut_t *)Abc_NodeGetCutsRecursive( pManCut, pNode, 0, 0 ); assert( pCut != NULL ); p->timeCut += Abc_Clock() - clk; //printf( " %d", Rwr_CutCountNumNodes(pNode, pCut) ); /* Counter = 0; for ( pTemp = pCut->pNext; pTemp; pTemp = pTemp->pNext ) Counter++; printf( "%d ", Counter ); */ // go through the cuts clk = Abc_Clock(); for ( pCut = pCut->pNext; pCut; pCut = pCut->pNext ) { // consider only 4-input cuts if ( pCut->nLeaves < 4 ) continue; // Cut_CutPrint( pCut, 0 ), printf( "\n" ); // get the fanin permutation uTruth = 0xFFFF & *Cut_CutReadTruth(pCut); pPerm = p->pPerms4[ (int)p->pPerms[uTruth] ]; uPhase = p->pPhases[uTruth]; // collect fanins with the corresponding permutation/phase Vec_PtrClear( p->vFaninsCur ); Vec_PtrFill( p->vFaninsCur, (int)pCut->nLeaves, 0 ); for ( i = 0; i < (int)pCut->nLeaves; i++ ) { pFanin = Abc_NtkObj( pNode->pNtk, pCut->pLeaves[(int)pPerm[i]] ); if ( pFanin == NULL ) break; pFanin = Abc_ObjNotCond(pFanin, ((uPhase & (1< 0) ); Vec_PtrWriteEntry( p->vFaninsCur, i, pFanin ); } if ( i != (int)pCut->nLeaves ) { p->nCutsBad++; continue; } p->nCutsGood++; { int Counter = 0; Vec_PtrForEachEntry( Abc_Obj_t *, p->vFaninsCur, pFanin, i ) if ( Abc_ObjFanoutNum(Abc_ObjRegular(pFanin)) == 1 ) Counter++; if ( Counter > 2 ) continue; } clk2 = Abc_Clock(); /* printf( "Considering: (" ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vFaninsCur, pFanin, i ) printf( "%d ", Abc_ObjFanoutNum(Abc_ObjRegular(pFanin)) ); printf( ")\n" ); */ // mark the fanin boundary Vec_PtrForEachEntry( Abc_Obj_t *, p->vFaninsCur, pFanin, i ) Abc_ObjRegular(pFanin)->vFanouts.nSize++; // label MFFC with current ID Abc_NtkIncrementTravId( pNode->pNtk ); nNodesSaved = Abc_NodeMffcLabelAig( pNode ); // unmark the fanin boundary Vec_PtrForEachEntry( Abc_Obj_t *, p->vFaninsCur, pFanin, i ) Abc_ObjRegular(pFanin)->vFanouts.nSize--; p->timeMffc += Abc_Clock() - clk2; // evaluate the cut clk2 = Abc_Clock(); pGraph = Rwr_CutEvaluate( p, pNode, pCut, p->vFaninsCur, nNodesSaved, Required, &GainCur, fPlaceEnable ); p->timeEval += Abc_Clock() - clk2; // check if the cut is better than the current best one if ( pGraph != NULL && GainBest < GainCur ) { // save this form nNodesSaveCur = nNodesSaved; GainBest = GainCur; p->pGraph = pGraph; p->fCompl = ((uPhase & (1<<4)) > 0); uTruthBest = 0xFFFF & *Cut_CutReadTruth(pCut); // collect fanins in the Vec_PtrClear( p->vFanins ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vFaninsCur, pFanin, i ) Vec_PtrPush( p->vFanins, pFanin ); } } p->timeRes += Abc_Clock() - clk; if ( GainBest == -1 ) return -1; /* if ( GainBest > 0 ) { printf( "Class %d ", p->pMap[uTruthBest] ); printf( "Gain = %d. Node %d : ", GainBest, pNode->Id ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vFanins, pFanin, i ) printf( "%d ", Abc_ObjRegular(pFanin)->Id ); Dec_GraphPrint( stdout, p->pGraph, NULL, NULL ); printf( "\n" ); } */ // printf( "%d", nNodesSaveCur - GainBest ); /* if ( GainBest > 0 ) { if ( Rwr_CutIsBoolean( pNode, p->vFanins ) ) printf( "b" ); else { printf( "Node %d : ", pNode->Id ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vFanins, pFanin, i ) printf( "%d ", Abc_ObjRegular(pFanin)->Id ); printf( "a" ); } } */ /* if ( GainBest > 0 ) if ( p->fCompl ) printf( "c" ); else printf( "." ); */ // copy the leaves Vec_PtrForEachEntry( Abc_Obj_t *, p->vFanins, pFanin, i ) Dec_GraphNode((Dec_Graph_t *)p->pGraph, i)->pFunc = pFanin; /* printf( "(" ); Vec_PtrForEachEntry( Abc_Obj_t *, p->vFanins, pFanin, i ) printf( " %d", Abc_ObjRegular(pFanin)->vFanouts.nSize - 1 ); printf( " ) " ); */ // printf( "%d ", Rwr_NodeGetDepth_rec( pNode, p->vFanins ) ); p->nScores[p->pMap[uTruthBest]]++; p->nNodesGained += GainBest; if ( fUseZeros || GainBest > 0 ) { p->nNodesRewritten++; } // report the progress if ( fVeryVerbose && GainBest > 0 ) { printf( "Node %6s : ", Abc_ObjName(pNode) ); printf( "Fanins = %d. ", p->vFanins->nSize ); printf( "Save = %d. ", nNodesSaveCur ); printf( "Add = %d. ", nNodesSaveCur-GainBest ); printf( "GAIN = %d. ", GainBest ); printf( "Cone = %d. ", p->pGraph? Dec_GraphNodeNum((Dec_Graph_t *)p->pGraph) : 0 ); printf( "Class = %d. ", p->pMap[uTruthBest] ); printf( "\n" ); } return GainBest; } /**Function************************************************************* Synopsis [Evaluates the cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Dec_Graph_t * Rwr_CutEvaluate( Rwr_Man_t * p, Abc_Obj_t * pRoot, Cut_Cut_t * pCut, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int LevelMax, int * pGainBest, int fPlaceEnable ) { extern int Dec_GraphToNetworkCount( Abc_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax, int LevelMax ); Vec_Ptr_t * vSubgraphs; Dec_Graph_t * pGraphBest = NULL; // Suppress "might be used uninitialized" Dec_Graph_t * pGraphCur; Rwr_Node_t * pNode, * pFanin; int nNodesAdded, GainBest, i, k; unsigned uTruth; float CostBest;//, CostCur; // find the matching class of subgraphs uTruth = 0xFFFF & *Cut_CutReadTruth(pCut); vSubgraphs = Vec_VecEntry( p->vClasses, p->pMap[uTruth] ); p->nSubgraphs += vSubgraphs->nSize; // determine the best subgraph GainBest = -1; CostBest = ABC_INFINITY; Vec_PtrForEachEntry( Rwr_Node_t *, vSubgraphs, pNode, i ) { // get the current graph pGraphCur = (Dec_Graph_t *)pNode->pNext; // copy the leaves Vec_PtrForEachEntry( Rwr_Node_t *, vFaninsCur, pFanin, k ) Dec_GraphNode(pGraphCur, k)->pFunc = pFanin; // detect how many unlabeled nodes will be reused nNodesAdded = Dec_GraphToNetworkCount( pRoot, pGraphCur, nNodesSaved, LevelMax ); if ( nNodesAdded == -1 ) continue; assert( nNodesSaved >= nNodesAdded ); /* // evaluate the cut if ( fPlaceEnable ) { extern float Abc_PlaceEvaluateCut( Abc_Obj_t * pRoot, Vec_Ptr_t * vFanins ); float Alpha = 0.5; // ??? float PlaceCost; // get the placement cost of the cut PlaceCost = Abc_PlaceEvaluateCut( pRoot, vFaninsCur ); // get the weigted cost of the cut CostCur = nNodesSaved - nNodesAdded + Alpha * PlaceCost; // do not allow uphill moves if ( nNodesSaved - nNodesAdded < 0 ) continue; // decide what cut to use if ( CostBest > CostCur ) { GainBest = nNodesSaved - nNodesAdded; // pure node cost CostBest = CostCur; // cost with placement pGraphBest = pGraphCur; // subgraph to be used for rewriting // score the graph if ( nNodesSaved - nNodesAdded > 0 ) { pNode->nScore++; pNode->nGain += GainBest; pNode->nAdded += nNodesAdded; } } } else */ { // count the gain at this node if ( GainBest < nNodesSaved - nNodesAdded ) { GainBest = nNodesSaved - nNodesAdded; pGraphBest = pGraphCur; // score the graph if ( nNodesSaved - nNodesAdded > 0 ) { pNode->nScore++; pNode->nGain += GainBest; pNode->nAdded += nNodesAdded; } } } } if ( GainBest == -1 ) return NULL; *pGainBest = GainBest; return pGraphBest; } /**Function************************************************************* Synopsis [Checks the type of the cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Rwr_CutIsBoolean_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves, int fMarkA ) { if ( Vec_PtrFind(vLeaves, pObj) >= 0 || Vec_PtrFind(vLeaves, Abc_ObjNot(pObj)) >= 0 ) { if ( fMarkA ) pObj->fMarkA = 1; else pObj->fMarkB = 1; return; } assert( !Abc_ObjIsCi(pObj) ); Rwr_CutIsBoolean_rec( Abc_ObjFanin0(pObj), vLeaves, fMarkA ); Rwr_CutIsBoolean_rec( Abc_ObjFanin1(pObj), vLeaves, fMarkA ); } /**Function************************************************************* Synopsis [Checks the type of the cut.] Description [Returns 1(0) if the cut is Boolean (algebraic).] SideEffects [] SeeAlso [] ***********************************************************************/ int Rwr_CutIsBoolean( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ) { Abc_Obj_t * pTemp; int i, RetValue; Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pTemp, i ) { pTemp = Abc_ObjRegular(pTemp); assert( !pTemp->fMarkA && !pTemp->fMarkB ); } Rwr_CutIsBoolean_rec( Abc_ObjFanin0(pObj), vLeaves, 1 ); Rwr_CutIsBoolean_rec( Abc_ObjFanin1(pObj), vLeaves, 0 ); RetValue = 0; Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pTemp, i ) { pTemp = Abc_ObjRegular(pTemp); RetValue |= pTemp->fMarkA && pTemp->fMarkB; pTemp->fMarkA = pTemp->fMarkB = 0; } return RetValue; } /**Function************************************************************* Synopsis [Count the nodes in the cut space of a node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Rwr_CutCountNumNodes_rec( Abc_Obj_t * pObj, Cut_Cut_t * pCut, Vec_Ptr_t * vNodes ) { int i; for ( i = 0; i < (int)pCut->nLeaves; i++ ) if ( pCut->pLeaves[i] == pObj->Id ) { // check if the node is collected if ( pObj->fMarkC == 0 ) { pObj->fMarkC = 1; Vec_PtrPush( vNodes, pObj ); } return; } assert( Abc_ObjIsNode(pObj) ); // check if the node is collected if ( pObj->fMarkC == 0 ) { pObj->fMarkC = 1; Vec_PtrPush( vNodes, pObj ); } // traverse the fanins Rwr_CutCountNumNodes_rec( Abc_ObjFanin0(pObj), pCut, vNodes ); Rwr_CutCountNumNodes_rec( Abc_ObjFanin1(pObj), pCut, vNodes ); } /**Function************************************************************* Synopsis [Count the nodes in the cut space of a node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Rwr_CutCountNumNodes( Abc_Obj_t * pObj, Cut_Cut_t * pCut ) { Vec_Ptr_t * vNodes; int i, Counter; // collect all nodes vNodes = Vec_PtrAlloc( 100 ); for ( pCut = pCut->pNext; pCut; pCut = pCut->pNext ) Rwr_CutCountNumNodes_rec( pObj, pCut, vNodes ); // clean all nodes Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) pObj->fMarkC = 0; // delete and return Counter = Vec_PtrSize(vNodes); Vec_PtrFree( vNodes ); return Counter; } /**Function************************************************************* Synopsis [Returns depth of the cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Rwr_NodeGetDepth_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLeaves ) { Abc_Obj_t * pLeaf; int i, Depth0, Depth1; if ( Abc_ObjIsCi(pObj) ) return 0; Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pLeaf, i ) if ( pObj == Abc_ObjRegular(pLeaf) ) return 0; Depth0 = Rwr_NodeGetDepth_rec( Abc_ObjFanin0(pObj), vLeaves ); Depth1 = Rwr_NodeGetDepth_rec( Abc_ObjFanin1(pObj), vLeaves ); return 1 + Abc_MaxInt( Depth0, Depth1 ); } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Rwr_ScoresClean( Rwr_Man_t * p ) { Vec_Ptr_t * vSubgraphs; Rwr_Node_t * pNode; int i, k; for ( i = 0; i < p->vClasses->nSize; i++ ) { vSubgraphs = Vec_VecEntry( p->vClasses, i ); Vec_PtrForEachEntry( Rwr_Node_t *, vSubgraphs, pNode, k ) pNode->nScore = pNode->nGain = pNode->nAdded = 0; } } static int Gains[222]; /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Rwr_ScoresCompare( int * pNum1, int * pNum2 ) { if ( Gains[*pNum1] > Gains[*pNum2] ) return -1; if ( Gains[*pNum1] < Gains[*pNum2] ) return 1; return 0; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Rwr_ScoresReport( Rwr_Man_t * p ) { extern void Ivy_TruthDsdComputePrint( unsigned uTruth ); int Perm[222]; Vec_Ptr_t * vSubgraphs; Rwr_Node_t * pNode; int i, iNew, k; unsigned uTruth; // collect total gains assert( p->vClasses->nSize == 222 ); for ( i = 0; i < p->vClasses->nSize; i++ ) { Perm[i] = i; Gains[i] = 0; vSubgraphs = Vec_VecEntry( p->vClasses, i ); Vec_PtrForEachEntry( Rwr_Node_t *, vSubgraphs, pNode, k ) Gains[i] += pNode->nGain; } // sort the gains qsort( Perm, 222, sizeof(int), (int (*)(const void *, const void *))Rwr_ScoresCompare ); // print classes for ( i = 0; i < p->vClasses->nSize; i++ ) { iNew = Perm[i]; if ( Gains[iNew] == 0 ) break; vSubgraphs = Vec_VecEntry( p->vClasses, iNew ); printf( "CLASS %3d: Subgr = %3d. Total gain = %6d. ", iNew, Vec_PtrSize(vSubgraphs), Gains[iNew] ); uTruth = (unsigned)p->pMapInv[iNew]; Extra_PrintBinary( stdout, &uTruth, 16 ); printf( " " ); Ivy_TruthDsdComputePrint( (unsigned)p->pMapInv[iNew] | ((unsigned)p->pMapInv[iNew] << 16) ); Vec_PtrForEachEntry( Rwr_Node_t *, vSubgraphs, pNode, k ) { if ( pNode->nScore == 0 ) continue; printf( " %2d: S=%5d. A=%5d. G=%6d. ", k, pNode->nScore, pNode->nAdded, pNode->nGain ); Dec_GraphPrint( stdout, (Dec_Graph_t *)pNode->pNext, NULL, NULL ); } } } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END