| /**CFile**************************************************************** |
| |
| FileName [abcRec2.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Network and node package.] |
| |
| Synopsis [Record of semi-canonical AIG subgraphs.] |
| |
| Author [Allan Yang, Alan Mishchenko] |
| |
| Affiliation [Fudan University in Shanghai, UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: abcRec.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "base/abc/abc.h" |
| #include "map/if/if.h" |
| #include "bool/kit/kit.h" |
| #include "aig/gia/giaAig.h" |
| #include "misc/vec/vecMem.h" |
| #include "opt/dau/dau.h" |
| #include "misc/util/utilTruth.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| #define LMS_VAR_MAX 16 // LMS_VAR_MAX >= 6 |
| #define LMS_MAX_WORD (1<<(LMS_VAR_MAX-6)) |
| //#define LMS_USE_OLD_FORM |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /* |
| This LMS manager can be used in two modes: |
| - library constuction |
| - AIG level minimization |
| To switch from library construction to AIG level minimization |
| LSM manager should be restarted by dumping GIA (rec_dump3 <file>.aig) |
| and starting LMS manager again (rec_start3 <file>.aig). |
| */ |
| |
| typedef struct Lms_Man_t_ Lms_Man_t; |
| struct Lms_Man_t_ |
| { |
| // parameters |
| int nVars; // the number of variables |
| int nWords; // the number of TT words |
| int nCuts; // the max number of cuts to use |
| int fFuncOnly; // record only functions |
| int fLibConstr; // this manager is used for library construction |
| // internal data for library construction |
| Gia_Man_t * pGia; // the record |
| Vec_Mem_t * vTtMem; // truth table memory and hash table |
| // Vec_Mem_t * vTtMem2; // truth table memory and hash table |
| Vec_Int_t * vTruthIds; // truth table IDs of each PO |
| // internal data for AIG level minimization (allocated the first time it is called) |
| Vec_Int_t * vTruthPo; // first PO where this canonicized truth table was seen |
| Vec_Wrd_t * vDelays; // pin-to-pin delays of each PO |
| Vec_Str_t * vAreas; // number of AND gates in each PO |
| Vec_Int_t * vFreqs; // subgraph usage frequencies |
| Vec_Int_t * vTruthFreqs; // truth table usage frequencies |
| // temporaries |
| Vec_Ptr_t * vNodes; // the temporary nodes |
| Vec_Ptr_t * vLabelsP; // temporary storage for HOP node labels |
| Vec_Int_t * vLabels; // temporary storage for AIG node labels |
| Vec_Str_t * vSupps; // used temporarily by TT dumping |
| word pTemp1[LMS_MAX_WORD]; // copy of the truth table |
| word pTemp2[LMS_MAX_WORD]; // copy of the truth table |
| // statistics |
| int nTried; |
| int nFilterSize; |
| int nFilterRedund; |
| int nFilterVolume; |
| int nFilterTruth; |
| int nFilterError; |
| int nFilterSame; |
| int nAdded; |
| int nAddedFuncs; |
| int nHoleInTheWall; |
| // runtime |
| abctime timeTruth; |
| abctime timeCanon; |
| abctime timeBuild; |
| abctime timeCheck; |
| abctime timeInsert; |
| abctime timeOther; |
| abctime timeTotal; |
| }; |
| |
| static Lms_Man_t * s_pMan3 = NULL; |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Compute delay/area profiles of POs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Lms_DelayGet( word D, int v ) { assert(v >= 0 && v < LMS_VAR_MAX); return (int)((D >> (v << 2)) & 0xF); } |
| static inline void Lms_DelaySet( word * pD, int v, int d ) { assert(v >= 0 && v < LMS_VAR_MAX); assert(d >= 0 && d < LMS_VAR_MAX); *pD |= ((word)d << (v << 2)); } |
| static inline word Lms_DelayInit( int v ) { assert(v >= 0 && v < LMS_VAR_MAX); return (word)1 << (v << 2); } |
| static inline word Lms_DelayMax( word D1, word D2, int nVars ) |
| { |
| int v, Max; |
| word D = 0; |
| for ( v = 0; v < nVars; v++ ) |
| if ( (Max = Abc_MaxInt(Lms_DelayGet(D1, v), Lms_DelayGet(D2, v))) ) |
| Lms_DelaySet( &D, v, Abc_MinInt(Max + 1, 15) ); |
| return D; |
| } |
| static inline word Lms_DelayDecrement( word D1, int nVars ) |
| { |
| int v; |
| word D = 0; |
| for ( v = 0; v < nVars; v++ ) |
| if ( Lms_DelayGet(D1, v) ) |
| Lms_DelaySet( &D, v, Lms_DelayGet(D1, v) - 1 ); |
| return D; |
| } |
| static inline int Lms_DelayEqual( word D1, word D2, int nVars ) // returns 1 if D1 has the same delays than D2 |
| { |
| int v; |
| for ( v = 0; v < nVars; v++ ) |
| if ( Lms_DelayGet(D1, v) != Lms_DelayGet(D2, v) ) |
| return 0; |
| return 1; |
| } |
| static inline int Lms_DelayDom( word D1, word D2, int nVars ) // returns 1 if D1 has the same or smaller delays than D2 |
| { |
| int v; |
| for ( v = 0; v < nVars; v++ ) |
| if ( Lms_DelayGet(D1, v) > Lms_DelayGet(D2, v) ) |
| return 0; |
| return 1; |
| } |
| static inline void Lms_DelayPrint( word D, int nVars ) |
| { |
| int v; |
| printf( "Delay profile = {" ); |
| for ( v = 0; v < nVars; v++ ) |
| printf( " %d", Lms_DelayGet(D, v) ); |
| printf( " }\n" ); |
| } |
| Vec_Wrd_t * Lms_GiaDelays( Gia_Man_t * p ) |
| { |
| Vec_Wrd_t * vDelays, * vResult; |
| Gia_Obj_t * pObj; |
| int i; |
| // compute delay profiles of all objects |
| vDelays = Vec_WrdAlloc( Gia_ManObjNum(p) ); |
| Vec_WrdPush( vDelays, 0 ); // const 0 |
| Gia_ManForEachObj1( p, pObj, i ) |
| { |
| if ( Gia_ObjIsAnd(pObj) ) |
| Vec_WrdPush( vDelays, Lms_DelayMax( Vec_WrdEntry(vDelays, Gia_ObjFaninId0(pObj, i)), Vec_WrdEntry(vDelays, Gia_ObjFaninId1(pObj, i)), Gia_ManCiNum(p) ) ); |
| else if ( Gia_ObjIsCo(pObj) ) |
| Vec_WrdPush( vDelays, Lms_DelayDecrement( Vec_WrdEntry(vDelays, Gia_ObjFaninId0(pObj, i)), Gia_ManCiNum(p) ) ); |
| else if ( Gia_ObjIsCi(pObj) ) |
| Vec_WrdPush( vDelays, Lms_DelayInit( Gia_ObjCioId(pObj) ) ); |
| else assert( 0 ); |
| } |
| // collect delay profiles of COs only |
| vResult = Vec_WrdAlloc( Gia_ManCoNum(p) ); |
| Gia_ManForEachCo( p, pObj, i ) |
| Vec_WrdPush( vResult, Vec_WrdEntry(vDelays, Gia_ObjId(p, pObj)) ); |
| Vec_WrdFree( vDelays ); |
| return vResult; |
| } |
| void Lms_ObjAreaMark_rec( Gia_Obj_t * pObj ) |
| { |
| if ( pObj->fMark0 || Gia_ObjIsCi(pObj) ) |
| return; |
| pObj->fMark0 = 1; |
| Lms_ObjAreaMark_rec( Gia_ObjFanin0(pObj) ); |
| Lms_ObjAreaMark_rec( Gia_ObjFanin1(pObj) ); |
| } |
| int Lms_ObjAreaUnmark_rec( Gia_Obj_t * pObj ) |
| { |
| if ( !pObj->fMark0 || Gia_ObjIsCi(pObj) ) |
| return 0; |
| pObj->fMark0 = 0; |
| return 1 + Lms_ObjAreaUnmark_rec( Gia_ObjFanin0(pObj) ) |
| + Lms_ObjAreaUnmark_rec( Gia_ObjFanin1(pObj) ); |
| } |
| int Lms_ObjArea( Gia_Obj_t * pObj ) |
| { |
| assert( Gia_ObjIsAnd(pObj) ); |
| Lms_ObjAreaMark_rec( pObj ); |
| return Lms_ObjAreaUnmark_rec( pObj ); |
| } |
| Vec_Str_t * Lms_GiaAreas( Gia_Man_t * p ) |
| { |
| Vec_Str_t * vAreas; |
| Gia_Obj_t * pObj; |
| int i; |
| vAreas = Vec_StrAlloc( Gia_ManCoNum(p) ); |
| Gia_ManForEachCo( p, pObj, i ) |
| Vec_StrPush( vAreas, (char)(Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) ? Lms_ObjArea(Gia_ObjFanin0(pObj)) : 0) ); |
| return vAreas; |
| } |
| Vec_Str_t * Lms_GiaSuppSizes( Gia_Man_t * p ) |
| { |
| Vec_Str_t * vResult; |
| Vec_Str_t * vSupps; |
| Gia_Obj_t * pObj; |
| int i; |
| vSupps = Vec_StrAlloc( Gia_ManObjNum(p) ); |
| Vec_StrPush( vSupps, 0 ); |
| Gia_ManForEachObj1( p, pObj, i ) |
| { |
| if ( Gia_ObjIsAnd(pObj) ) |
| Vec_StrPush( vSupps, (char)Abc_MaxInt( Vec_StrEntry(vSupps, Gia_ObjFaninId0(pObj, i)), Vec_StrEntry(vSupps, Gia_ObjFaninId1(pObj, i)) ) ); |
| else if ( Gia_ObjIsCo(pObj) ) |
| Vec_StrPush( vSupps, Vec_StrEntry(vSupps, Gia_ObjFaninId0(pObj, i)) ); |
| else if ( Gia_ObjIsCi(pObj) ) |
| Vec_StrPush( vSupps, (char)(Gia_ObjCioId(pObj)+1) ); |
| else assert( 0 ); |
| } |
| assert( Vec_StrSize(vSupps) == Gia_ManObjNum(p) ); |
| vResult = Vec_StrAlloc( Gia_ManCoNum(p) ); |
| Gia_ManForEachCo( p, pObj, i ) |
| Vec_StrPush( vResult, Vec_StrEntry(vSupps, Gia_ObjId(p, pObj)) ); |
| Vec_StrFree( vSupps ); |
| return vResult; |
| } |
| void Lms_GiaProfilesPrint( Gia_Man_t * p ) |
| { |
| Gia_Obj_t * pObj; |
| int i; |
| Vec_Wrd_t * vDelays; |
| Vec_Str_t * vAreas; |
| vDelays = Lms_GiaDelays( p ); |
| vAreas = Lms_GiaAreas( p ); |
| Gia_ManForEachPo( p, pObj, i ) |
| { |
| printf( "%6d : ", i ); |
| printf( "A = %2d ", Vec_StrEntry(vAreas, i) ); |
| Lms_DelayPrint( Vec_WrdEntry(vDelays, i), Gia_ManPiNum(p) ); |
| // Lms_GiaPrintSubgraph( p, pObj ); |
| // printf( "\n" ); |
| } |
| Vec_WrdFree( vDelays ); |
| Vec_StrFree( vAreas ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints one GIA subgraph.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Lms_GiaPrintSubgraph_rec( Gia_Man_t * p, Gia_Obj_t * pObj ) |
| { |
| if ( !pObj->fMark0 || Gia_ObjIsCi(pObj) ) |
| return; |
| pObj->fMark0 = 0; |
| assert( Gia_ObjIsAnd(pObj) ); |
| Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin0(pObj) ); |
| Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin1(pObj) ); |
| Gia_ObjPrint( p, pObj ); |
| } |
| void Lms_GiaPrintSubgraph( Gia_Man_t * p, Gia_Obj_t * pObj ) |
| { |
| assert( Gia_ObjIsCo(pObj) ); |
| if ( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) ) |
| { |
| Lms_ObjAreaMark_rec( Gia_ObjFanin0(pObj) ); |
| Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin0(pObj) ); |
| } |
| else |
| Gia_ObjPrint( p, Gia_ObjFanin0(pObj) ); |
| Gia_ObjPrint( p, pObj ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Lms_Man_t * Lms_ManStart( Gia_Man_t * pGia, int nVars, int nCuts, int fFuncOnly, int fVerbose ) |
| { |
| Lms_Man_t * p; |
| abctime clk, clk2 = Abc_Clock(); |
| // if GIA is given, use the number of variables from GIA |
| nVars = pGia ? Gia_ManCiNum(pGia) : nVars; |
| assert( nVars >= 6 && nVars <= LMS_VAR_MAX ); |
| // allocate manager |
| p = ABC_CALLOC( Lms_Man_t, 1 ); |
| // parameters |
| p->nVars = nVars; |
| p->nCuts = nCuts; |
| p->nWords = Abc_Truth6WordNum( nVars ); |
| p->fFuncOnly = fFuncOnly; |
| // internal data for library construction |
| p->vTtMem = Vec_MemAlloc( p->nWords, 12 ); // 32 KB/page for 6-var functions |
| // p->vTtMem2 = Vec_MemAlloc( p->nWords, 12 ); // 32 KB/page for 6-var functions |
| Vec_MemHashAlloc( p->vTtMem, 10000 ); |
| // Vec_MemHashAlloc( p->vTtMem2, 10000 ); |
| if ( fFuncOnly ) |
| return p; |
| p->vTruthIds = Vec_IntAlloc( 10000 ); |
| if ( pGia == NULL ) |
| { |
| int i; |
| p->pGia = Gia_ManStart( 10000 ); |
| p->pGia->pName = Abc_UtilStrsav( "record" ); |
| for ( i = 0; i < nVars; i++ ) |
| Gia_ManAppendCi( p->pGia ); |
| } |
| else |
| { |
| Gia_Obj_t * pObj; |
| word * pTruth; |
| int i, Index, Prev = -1; |
| p->pGia = pGia; |
| // populate the manager with subgraphs present in GIA |
| p->nAdded = Gia_ManCoNum( p->pGia ); |
| Gia_ManForEachCo( p->pGia, pObj, i ) |
| { |
| clk = Abc_Clock(); |
| pTruth = Gia_ObjComputeTruthTable( p->pGia, pObj ); |
| p->timeTruth += Abc_Clock() - clk; |
| clk = Abc_Clock(); |
| Index = Vec_MemHashInsert( p->vTtMem, pTruth ); |
| p->timeInsert += Abc_Clock() - clk; |
| assert( Index == Prev || Index == Prev + 1 ); // GIA subgraphs should be ordered |
| Vec_IntPush( p->vTruthIds, Index ); |
| Prev = Index; |
| } |
| } |
| // temporaries |
| p->vNodes = Vec_PtrAlloc( 1000 ); |
| p->vLabelsP = Vec_PtrAlloc( 1000 ); |
| p->vLabels = Vec_IntAlloc( 1000 ); |
| p->timeTotal += Abc_Clock() - clk2; |
| return p; |
| } |
| void Lms_ManStop( Lms_Man_t * p ) |
| { |
| // temporaries |
| Vec_IntFreeP( &p->vLabels ); |
| Vec_PtrFreeP( &p->vLabelsP ); |
| Vec_PtrFreeP( &p->vNodes ); |
| // internal data for AIG level minimization |
| Vec_IntFreeP( &p->vTruthPo ); |
| Vec_WrdFreeP( &p->vDelays ); |
| Vec_StrFreeP( &p->vAreas ); |
| Vec_IntFreeP( &p->vFreqs ); |
| Vec_IntFreeP( &p->vTruthFreqs ); |
| // internal data for library construction |
| Vec_IntFreeP( &p->vTruthIds ); |
| Vec_MemHashFree( p->vTtMem ); |
| // Vec_MemHashFree( p->vTtMem2 ); |
| Vec_MemFree( p->vTtMem ); |
| // Vec_MemFree( p->vTtMem2 ); |
| Gia_ManStopP( &p->pGia ); |
| ABC_FREE( p ); |
| } |
| void Lms_ManPrepare( Lms_Man_t * p ) |
| { |
| // compute the first PO for each semi-canonical form |
| int i, Entry; |
| assert( !p->fLibConstr ); |
| assert( p->vTruthPo == NULL ); |
| p->vTruthPo = Vec_IntStartFull( Vec_MemEntryNum(p->vTtMem)+1 ); |
| assert( Vec_IntFindMin(p->vTruthIds) >= 0 ); |
| assert( Vec_IntFindMax(p->vTruthIds) < Vec_MemEntryNum(p->vTtMem) ); |
| Vec_IntForEachEntry( p->vTruthIds, Entry, i ) |
| if ( Vec_IntEntry(p->vTruthPo, Entry) == -1 ) |
| Vec_IntWriteEntry( p->vTruthPo, Entry, i ); |
| Vec_IntWriteEntry( p->vTruthPo, Vec_MemEntryNum(p->vTtMem), Gia_ManCoNum(p->pGia) ); |
| // compute delay/area and init frequency |
| assert( p->vDelays == NULL ); |
| assert( p->vAreas == NULL ); |
| assert( p->vFreqs == NULL ); |
| p->vDelays = Lms_GiaDelays( p->pGia ); |
| p->vAreas = Lms_GiaAreas( p->pGia ); |
| p->vFreqs = Vec_IntStart( Gia_ManCoNum(p->pGia) ); |
| } |
| void Lms_ManPrintFuncStats( Lms_Man_t * p ) |
| { |
| Vec_Str_t * vSupps; |
| int Counters[LMS_VAR_MAX+1] = {0}, CountersS[LMS_VAR_MAX+1] = {0}; |
| int i, Entry, Next; |
| if ( p->pGia == NULL ) |
| return; |
| if ( p->fLibConstr ) |
| return; |
| if ( p->vTruthPo == NULL ) |
| Lms_ManPrepare( p ); |
| vSupps = Lms_GiaSuppSizes( p->pGia ); |
| Vec_IntForEachEntry( p->vTruthPo, Entry, i ) |
| { |
| if ( i == Vec_IntSize(p->vTruthPo) - 1 ) |
| break; |
| Next = Vec_IntEntry( p->vTruthPo, i+1 ); |
| Counters[(int)Vec_StrEntry(vSupps, Entry)]++; |
| CountersS[(int)Vec_StrEntry(vSupps, Entry)] += Next - Entry; |
| } |
| for ( i = 0; i <= LMS_VAR_MAX; i++ ) |
| if ( Counters[i] ) |
| printf( "Inputs = %2d. Funcs = %8d. Subgrs = %8d. Ratio = %6.2f.\n", i, Counters[i], CountersS[i], 1.0*CountersS[i]/Counters[i] ); |
| Vec_StrFree( vSupps ); |
| } |
| void Lms_ManPrintFreqStats( Lms_Man_t * p ) |
| { |
| int CountDsdNpn[3] = {0}; // full/part/none |
| int CountDsdAll[3] = {0}; // full/part/none |
| int CountStepNpn[3] = {0}; // full/1step/complex |
| int CountStepAll[3] = {0}; // full/1step/complex |
| char pBuffer[1000]; |
| int nSuppSize; |
| int nNonDecSize; |
| word * pTruth; |
| int i, Freq, Status; |
| printf( "Cuts = %10d. ", p->nTried ); |
| // printf( "Funcs = %10d (%6.2f %%). ", Vec_MemEntryNum(p->vTtMem2), 100.0*Vec_MemEntryNum(p->vTtMem2)/p->nTried ); |
| printf( "Class = %10d (%6.2f %%). ", Vec_MemEntryNum(p->vTtMem), 100.0*Vec_MemEntryNum(p->vTtMem)/p->nTried ); |
| printf( "\n" ); |
| // return; |
| |
| Vec_IntForEachEntry( p->vTruthFreqs, Freq, i ) |
| { |
| pTruth = Vec_MemReadEntry(p->vTtMem, i); |
| /* |
| printf( "%6d -- %6d : ", i, Freq ); |
| Kit_DsdWriteFromTruth( pBuffer, (unsigned *)pTruth, p->nVars ); |
| printf( "%s\n", pBuffer ); |
| */ |
| nSuppSize = Abc_TtSupportSize( pTruth, p->nVars ); |
| nNonDecSize = Dau_DsdDecompose( pTruth, p->nVars, 0, 0, pBuffer ); |
| if ( nNonDecSize == 0 ) |
| { |
| CountDsdNpn[0]++; |
| CountDsdAll[0] += Freq; |
| } |
| else if ( nNonDecSize < nSuppSize ) |
| { |
| CountDsdNpn[1]++; |
| CountDsdAll[1] += Freq; |
| } |
| else // non-dec |
| { |
| CountDsdNpn[2]++; |
| CountDsdAll[2] += Freq; |
| } |
| |
| if ( nNonDecSize == 0 ) |
| { |
| CountStepNpn[0]++; |
| CountStepAll[0] += Freq; |
| continue; |
| } |
| |
| // check the non dec core |
| Status = Dau_DsdCheck1Step( NULL, pTruth, nNonDecSize, NULL ); |
| if ( Status >= 0 ) |
| { |
| CountStepNpn[1]++; |
| CountStepAll[1] += Freq; |
| } |
| else |
| { |
| assert( Status == -2 ); |
| CountStepNpn[2]++; |
| CountStepAll[2] += Freq; |
| } |
| } |
| |
| // print the results |
| printf( "NPN: " ); |
| printf( "Full = %6.2f %% ", 100.0 * CountDsdNpn[0] / Vec_MemEntryNum(p->vTtMem) ); |
| printf( "Part = %6.2f %% ", 100.0 * CountDsdNpn[1] / Vec_MemEntryNum(p->vTtMem) ); |
| printf( "None = %6.2f %% ", 100.0 * CountDsdNpn[2] / Vec_MemEntryNum(p->vTtMem) ); |
| // printf( "\n" ); |
| printf( " " ); |
| // print the results |
| printf( "All: " ); |
| printf( "Full = %6.2f %% ", 100.0 * CountDsdAll[0] / p->nTried ); |
| printf( "Part = %6.2f %% ", 100.0 * CountDsdAll[1] / p->nTried ); |
| printf( "None = %6.2f %% ", 100.0 * CountDsdAll[2] / p->nTried ); |
| printf( "\n" ); |
| |
| // print the results |
| printf( "NPN: " ); |
| printf( "Full = %6.2f %% ", 100.0 * CountStepNpn[0] / Vec_MemEntryNum(p->vTtMem) ); |
| printf( "1stp = %6.2f %% ", 100.0 * CountStepNpn[1] / Vec_MemEntryNum(p->vTtMem) ); |
| printf( "Comp = %6.2f %% ", 100.0 * CountStepNpn[2] / Vec_MemEntryNum(p->vTtMem) ); |
| // printf( "\n" ); |
| printf( " " ); |
| // print the results |
| printf( "All: " ); |
| printf( "Full = %6.2f %% ", 100.0 * CountStepAll[0] / p->nTried ); |
| printf( "1stp = %6.2f %% ", 100.0 * CountStepAll[1] / p->nTried ); |
| printf( "Comp = %6.2f %% ", 100.0 * CountStepAll[2] / p->nTried ); |
| printf( "\n" ); |
| |
| } |
| void Lms_ManPrint( Lms_Man_t * p ) |
| { |
| // Gia_ManPrintStats( p->pGia, 0, 0 ); |
| printf( "Library with %d vars has %d classes and %d AIG subgraphs with %d AND nodes.\n", |
| p->nVars, Vec_MemEntryNum(p->vTtMem), p->nAdded, p->pGia ? Gia_ManAndNum(p->pGia) : 0 ); |
| |
| // Lms_ManPrintFreqStats( p ); |
| Lms_ManPrintFuncStats( p ); |
| |
| p->nAddedFuncs = Vec_MemEntryNum(p->vTtMem); |
| printf( "Subgraphs tried = %10d. (%6.2f %%)\n", p->nTried, !p->nTried? 0 : 100.0*p->nTried/p->nTried ); |
| printf( "Subgraphs filtered by support size = %10d. (%6.2f %%)\n", p->nFilterSize, !p->nTried? 0 : 100.0*p->nFilterSize/p->nTried ); |
| printf( "Subgraphs filtered by structural redundancy = %10d. (%6.2f %%)\n", p->nFilterRedund, !p->nTried? 0 : 100.0*p->nFilterRedund/p->nTried ); |
| printf( "Subgraphs filtered by volume = %10d. (%6.2f %%)\n", p->nFilterVolume, !p->nTried? 0 : 100.0*p->nFilterVolume/p->nTried ); |
| printf( "Subgraphs filtered by TT redundancy = %10d. (%6.2f %%)\n", p->nFilterTruth, !p->nTried? 0 : 100.0*p->nFilterTruth/p->nTried ); |
| printf( "Subgraphs filtered by error = %10d. (%6.2f %%)\n", p->nFilterError, !p->nTried? 0 : 100.0*p->nFilterError/p->nTried ); |
| printf( "Subgraphs filtered by isomorphism = %10d. (%6.2f %%)\n", p->nFilterSame, !p->nTried? 0 : 100.0*p->nFilterSame/p->nTried ); |
| printf( "Subgraphs added = %10d. (%6.2f %%)\n", p->nAdded, !p->nTried? 0 : 100.0*p->nAdded/p->nTried ); |
| printf( "Functions added = %10d. (%6.2f %%)\n", p->nAddedFuncs, !p->nTried? 0 : 100.0*p->nAddedFuncs/p->nTried ); |
| if ( p->nHoleInTheWall ) |
| printf( "Cuts whose logic structure has a hole = %10d. (%6.2f %%)\n", p->nHoleInTheWall, !p->nTried? 0 : 100.0*p->nHoleInTheWall/p->nTried ); |
| |
| p->timeOther = p->timeTotal - p->timeTruth - p->timeCanon - p->timeBuild - p->timeCheck - p->timeInsert; |
| ABC_PRTP( "Runtime: Truth ", p->timeTruth, p->timeTotal ); |
| ABC_PRTP( "Runtime: Canon ", p->timeCanon, p->timeTotal ); |
| ABC_PRTP( "Runtime: Build ", p->timeBuild, p->timeTotal ); |
| ABC_PRTP( "Runtime: Check ", p->timeCheck, p->timeTotal ); |
| ABC_PRTP( "Runtime: Insert", p->timeInsert, p->timeTotal ); |
| ABC_PRTP( "Runtime: Other ", p->timeOther, p->timeTotal ); |
| ABC_PRTP( "Runtime: TOTAL ", p->timeTotal, p->timeTotal ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Recanonicizes the library and add it to the current library.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkRecLibMerge3( Gia_Man_t * pLib ) |
| { |
| int fCheck = 0; |
| Lms_Man_t * p = s_pMan3; |
| Gia_Man_t * pGia = p->pGia; |
| Vec_Str_t * vSupps; |
| char pCanonPerm[LMS_VAR_MAX]; |
| unsigned uCanonPhase; |
| word * pTruth; |
| int i, k, Index, iFanin0, iFanin1, nLeaves; |
| Gia_Obj_t * pObjPo, * pDriver, * pTemp = NULL; |
| abctime clk, clk2 = Abc_Clock(); |
| |
| if ( Gia_ManCiNum(pLib) != Gia_ManCiNum(pGia) ) |
| { |
| printf( "The number of Library inputs (%d) differs from the number of Gia inputs (%d).\n", Gia_ManCiNum(pLib), Gia_ManCiNum(pGia) ); |
| return; |
| } |
| assert( Gia_ManCiNum(pLib) == Gia_ManCiNum(pGia) ); |
| |
| // create hash table if not available |
| if ( Vec_IntSize(&pGia->vHTable) == 0 ) |
| Gia_ManHashStart( pGia ); |
| |
| // add AIG subgraphs |
| vSupps = Lms_GiaSuppSizes( pLib ); |
| Gia_ManForEachCo( pLib, pObjPo, k ) |
| { |
| // get support size |
| nLeaves = Vec_StrEntry(vSupps, k); |
| assert( nLeaves > 1 ); |
| |
| // compute the truth table |
| clk = Abc_Clock(); |
| pTruth = Gia_ObjComputeTruthTable( pLib, Gia_ObjFanin0(pObjPo) ); |
| p->timeTruth += Abc_Clock() - clk; |
| // semi-canonicize |
| clk = Abc_Clock(); |
| memcpy( p->pTemp1, pTruth, p->nWords * sizeof(word) ); |
| #ifdef LMS_USE_OLD_FORM |
| uCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm ); |
| #else |
| uCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm ); |
| #endif |
| Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars ); |
| p->timeCanon += Abc_Clock() - clk; |
| // pCanonPerm and uCanonPhase show what was the variable corresponding to each var in the current truth |
| if ( nLeaves == 2 && Abc_TtSupportSize(pTruth, 2) != 2 ) |
| continue; |
| |
| clk = Abc_Clock(); |
| // map cut leaves into elementary variables of GIA |
| for ( i = 0; i < nLeaves; i++ ) |
| Gia_ManCi( pLib, pCanonPerm[i] )->Value = Abc_Var2Lit( Gia_ObjId(pGia, Gia_ManPi(pGia, i)), (uCanonPhase >> i) & 1 ); |
| // build internal nodes |
| assert( Vec_IntSize(pLib->vTtNodes) > 0 ); |
| Gia_ManForEachObjVec( pLib->vTtNodes, pLib, pTemp, i ) |
| { |
| iFanin0 = Abc_LitNotCond( Gia_ObjFanin0(pTemp)->Value, Gia_ObjFaninC0(pTemp) ); |
| iFanin1 = Abc_LitNotCond( Gia_ObjFanin1(pTemp)->Value, Gia_ObjFaninC1(pTemp) ); |
| pTemp->Value = Gia_ManHashAnd( pGia, iFanin0, iFanin1 ); |
| } |
| p->timeBuild += Abc_Clock() - clk; |
| |
| // check if this node is already driving a PO |
| assert( Gia_ObjIsAnd(pTemp) ); |
| pDriver = Gia_ManObj(pGia, Abc_Lit2Var(pTemp->Value)); |
| if ( pDriver->fMark1 ) |
| { |
| p->nFilterSame++; |
| continue; |
| } |
| pDriver->fMark1 = 1; |
| // create output |
| Gia_ManAppendCo( pGia, Abc_LitNotCond( pTemp->Value, (uCanonPhase >> nLeaves) & 1 ) ); |
| |
| // verify truth table |
| if ( fCheck ) |
| { |
| clk = Abc_Clock(); |
| pTemp = Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1); |
| pTruth = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1) ); |
| p->timeCheck += Abc_Clock() - clk; |
| if ( memcmp( p->pTemp1, pTruth, p->nWords * sizeof(word) ) != 0 ) |
| { |
| |
| Kit_DsdPrintFromTruth( (unsigned *)pTruth, nLeaves ); printf( "\n" ); |
| Kit_DsdPrintFromTruth( (unsigned *)p->pTemp1, nLeaves ); printf( "\n" ); |
| printf( "Truth table verification has failed.\n" ); |
| |
| // drive PO with constant |
| Gia_ManPatchCoDriver( pGia, Gia_ManCoNum(pGia)-1, 0 ); |
| // save truth table ID |
| Vec_IntPush( p->vTruthIds, -1 ); |
| p->nFilterTruth++; |
| continue; |
| } |
| } |
| |
| clk = Abc_Clock(); |
| // add the resulting truth table to the hash table |
| Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 ); |
| // save truth table ID |
| Vec_IntPush( p->vTruthIds, Index ); |
| assert( Gia_ManCoNum(pGia) == Vec_IntSize(p->vTruthIds) ); |
| p->nAdded++; |
| p->timeInsert += Abc_Clock() - clk; |
| } |
| Vec_StrFree( vSupps ); |
| p->timeTotal += Abc_Clock() - clk2; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Evaluates one cut during library construction.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkRecAddCut3( If_Man_t * pIfMan, If_Obj_t * pRoot, If_Cut_t * pCut ) |
| { |
| Lms_Man_t * p = s_pMan3; |
| char pCanonPerm[LMS_VAR_MAX]; |
| unsigned uCanonPhase; |
| int i, Index, iFanin0, iFanin1, fHole; |
| int nLeaves = If_CutLeaveNum(pCut); |
| Vec_Ptr_t * vNodes = p->vNodes; |
| Gia_Man_t * pGia = p->pGia; |
| Gia_Obj_t * pDriver; |
| If_Obj_t * pIfObj = NULL; |
| word * pTruth; |
| abctime clk; |
| p->nTried++; |
| |
| // skip small cuts |
| assert( p->nVars == (int)pCut->nLimit ); |
| if ( nLeaves < 2 || (nLeaves == 2 && Abc_TtSupportSize(If_CutTruthW(pIfMan, pCut), 2) != 2) ) |
| { |
| p->nFilterSize++; |
| return 1; |
| } |
| |
| // if ( p->vTtMem2 ) |
| // Vec_MemHashInsert( p->vTtMem2, If_CutTruthW(pCut) ); |
| |
| // semi-canonicize truth table |
| clk = Abc_Clock(); |
| memcpy( p->pTemp1, If_CutTruthW(pIfMan, pCut), p->nWords * sizeof(word) ); |
| #ifdef LMS_USE_OLD_FORM |
| uCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm ); |
| #else |
| uCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm ); |
| #endif |
| Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars ); |
| p->timeCanon += Abc_Clock() - clk; |
| // pCanonPerm and uCanonPhase show what was the variable corresponding to each var in the current truth |
| |
| if ( p->pGia == NULL ) |
| { |
| clk = Abc_Clock(); |
| // add the resulting truth table to the hash table |
| Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 ); |
| /* |
| if ( p->vTruthFreqs == NULL ) |
| p->vTruthFreqs = Vec_IntAlloc( 1000 ); |
| assert( Index <= Vec_IntSize(p->vTruthFreqs) ); |
| if ( Index < Vec_IntSize(p->vTruthFreqs) ) |
| Vec_IntAddToEntry( p->vTruthFreqs, Index, 1 ); |
| else |
| Vec_IntPush( p->vTruthFreqs, 1 ); |
| */ |
| p->nAdded++; |
| p->timeInsert += Abc_Clock() - clk; |
| return 1; |
| } |
| |
| // collect internal nodes and skip redundant cuts |
| clk = Abc_Clock(); |
| If_CutTraverse( pIfMan, pRoot, pCut, vNodes ); |
| p->timeTruth += Abc_Clock() - clk; |
| if ( Vec_PtrSize(vNodes) > 253 ) |
| { |
| p->nFilterSize++; |
| return 1; |
| } |
| |
| clk = Abc_Clock(); |
| // map cut leaves into elementary variables of GIA |
| for ( i = 0; i < nLeaves; i++ ) |
| If_ManObj( pIfMan, pCut->pLeaves[(int)pCanonPerm[i]] )->iCopy = Abc_Var2Lit( Gia_ObjId(pGia, Gia_ManPi(pGia, i)), (uCanonPhase >> i) & 1 ); |
| // build internal nodes |
| fHole = 0; |
| assert( Vec_PtrSize(vNodes) > 0 ); |
| Vec_PtrForEachEntryStart( If_Obj_t *, vNodes, pIfObj, i, nLeaves ) |
| { |
| if ( If_ObjIsCi(pIfObj) ) |
| { |
| pIfObj->iCopy = 0; |
| fHole = 1; |
| continue; |
| } |
| iFanin0 = Abc_LitNotCond( If_ObjFanin0(pIfObj)->iCopy, If_ObjFaninC0(pIfObj) ); |
| iFanin1 = Abc_LitNotCond( If_ObjFanin1(pIfObj)->iCopy, If_ObjFaninC1(pIfObj) ); |
| pIfObj->iCopy = Gia_ManHashAnd( pGia, iFanin0, iFanin1 ); |
| } |
| p->nHoleInTheWall += fHole; |
| p->timeBuild += Abc_Clock() - clk; |
| |
| // check if this node is already driving a PO |
| assert( If_ObjIsAnd(pIfObj) ); |
| pDriver = Gia_ManObj(pGia, Abc_Lit2Var(pIfObj->iCopy)); |
| if ( pDriver->fMark1 ) |
| { |
| p->nFilterSame++; |
| return 1; |
| } |
| pDriver->fMark1 = 1; |
| // create output |
| Gia_ManAppendCo( pGia, Abc_LitNotCond( pIfObj->iCopy, (uCanonPhase >> nLeaves) & 1 ) ); |
| |
| // verify truth table |
| clk = Abc_Clock(); |
| pTruth = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1) ); |
| p->timeCheck += Abc_Clock() - clk; |
| if ( memcmp( p->pTemp1, pTruth, p->nWords * sizeof(word) ) != 0 ) |
| { |
| /* |
| Kit_DsdPrintFromTruth( pTruth, nLeaves ); printf( "\n" ); |
| Kit_DsdPrintFromTruth( (unsigned *)p->pTemp1, nLeaves ); printf( "\n" ); |
| printf( "Truth table verification has failed.\n" ); |
| */ |
| // drive PO with constant |
| Gia_ManPatchCoDriver( pGia, Gia_ManCoNum(pGia)-1, 0 ); |
| // save truth table ID |
| Vec_IntPush( p->vTruthIds, -1 ); |
| p->nFilterTruth++; |
| return 1; |
| } |
| |
| clk = Abc_Clock(); |
| // add the resulting truth table to the hash table |
| Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 ); |
| // save truth table ID |
| Vec_IntPush( p->vTruthIds, Index ); |
| assert( Gia_ManCoNum(pGia) == Vec_IntSize(p->vTruthIds) ); |
| p->nAdded++; |
| p->timeInsert += Abc_Clock() - clk; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Top level procedure for library construction.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkRecAdd3( Abc_Ntk_t * pNtk, int fUseSOPB ) |
| { |
| extern Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars ); |
| If_Par_t Pars, * pPars = &Pars; |
| Abc_Ntk_t * pNtkNew; |
| int clk = Abc_Clock(); |
| if ( Abc_NtkGetChoiceNum( pNtk ) ) |
| printf( "Performing recoding structures with choices.\n" ); |
| // remember that the manager was used for library construction |
| s_pMan3->fLibConstr = 1; |
| // create hash table if not available |
| if ( s_pMan3->pGia && Vec_IntSize(&s_pMan3->pGia->vHTable) == 0 ) |
| Gia_ManHashStart( s_pMan3->pGia ); |
| |
| // set defaults |
| memset( pPars, 0, sizeof(If_Par_t) ); |
| // user-controlable paramters |
| pPars->nLutSize = s_pMan3->nVars; |
| pPars->nCutsMax = s_pMan3->nCuts; |
| pPars->DelayTarget = -1; |
| pPars->Epsilon = (float)0.005; |
| pPars->fArea = 1; |
| // internal parameters |
| if ( fUseSOPB ) |
| { |
| pPars->fTruth = 1; |
| pPars->fCutMin = 0; |
| pPars->fUsePerm = 1; |
| pPars->fDelayOpt = 1; |
| } |
| else |
| { |
| pPars->fTruth = 1; |
| pPars->fCutMin = 1; |
| pPars->fUsePerm = 0; |
| pPars->fDelayOpt = 0; |
| } |
| pPars->fSkipCutFilter = 0; |
| pPars->pFuncCost = NULL; |
| pPars->pFuncUser = Abc_NtkRecAddCut3; |
| // perform recording |
| pNtkNew = Abc_NtkIf( pNtk, pPars ); |
| Abc_NtkDelete( pNtkNew ); |
| s_pMan3->timeTotal += Abc_Clock() - clk; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns min AIG level at the output fo the cut using the library.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int If_CutComputeDelay( If_Man_t * p, If_Cut_t * pCut, char * pCanonPerm, word DelayProfile ) |
| { |
| If_Obj_t* pLeaf; |
| int nLeaves = If_CutLeaveNum(pCut); |
| int i, delayTemp, delayMax = -ABC_INFINITY; |
| for ( i = 0; i < nLeaves; i++ ) |
| { |
| pLeaf = If_ManObj(p, (pCut)->pLeaves[(int)pCanonPerm[i]]); |
| delayTemp = If_ObjCutBest(pLeaf)->Delay + Lms_DelayGet(DelayProfile, i); |
| delayMax = Abc_MaxInt( delayMax, delayTemp ); |
| } |
| return delayMax; |
| } |
| static inline int If_CutFindBestStruct( If_Man_t * pIfMan, If_Cut_t * pCut, char * pCanonPerm, unsigned * puCanonPhase, int * pBestPo ) |
| { |
| Lms_Man_t * p = s_pMan3; |
| int i, * pTruthId, iFirstPo, iFirstPoNext, iBestPo; |
| int BestDelay = ABC_INFINITY, BestArea = ABC_INFINITY, Delay, Area; |
| int uSupport, nLeaves = If_CutLeaveNum( pCut ); |
| char * pPerm = If_CutPerm( pCut ); |
| word DelayProfile; |
| abctime clk; |
| pCut->fUser = 1; |
| // compute support |
| uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves ); |
| if ( uSupport == 0 ) |
| { |
| pCut->Cost = 1; |
| for ( i = 0; i < nLeaves; i++ ) |
| pPerm[i] = IF_BIG_CHAR; |
| return 0; |
| } |
| if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 ) |
| { |
| assert( Abc_TtSuppOnlyOne(uSupport) ); |
| pCut->Cost = 1; |
| for ( i = 0; i < nLeaves; i++ ) |
| pPerm[i] = IF_BIG_CHAR; |
| pPerm[Abc_TtSuppFindFirst(uSupport)] = 0; |
| return If_ObjCutBest(If_ManObj(pIfMan, pCut->pLeaves[Abc_TtSuppFindFirst(uSupport)]))->Delay; |
| } |
| assert( Gia_WordCountOnes(uSupport) == nLeaves ); |
| |
| // semicanonicize the function |
| clk = Abc_Clock(); |
| memcpy( p->pTemp1, If_CutTruthW(pIfMan, pCut), p->nWords * sizeof(word) ); |
| #ifdef LMS_USE_OLD_FORM |
| *puCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm ); |
| #else |
| *puCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm ); |
| #endif |
| Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars ); |
| p->timeCanon += Abc_Clock() - clk; |
| |
| // get TT ID for the given class |
| pTruthId = Vec_MemHashLookup( p->vTtMem, p->pTemp1 ); |
| if ( *pTruthId == -1 ) |
| { |
| pCut->Cost = IF_COST_MAX; |
| pCut->fUseless = 1; |
| return ABC_INFINITY; |
| } |
| |
| // note that array p->vTruthPo contains the first PO for the given truth table |
| // other POs belonging to the same equivalence class follow immediately after this one |
| // to iterate through the POs, we need to perform the following steps |
| |
| // find the first PO of this class |
| iFirstPo = Vec_IntEntry( p->vTruthPo, *pTruthId ); |
| // find the first PO of the next class |
| iFirstPoNext = Vec_IntEntry( p->vTruthPo, *pTruthId+1 ); |
| // iterate through the subgraphs of this class |
| iBestPo = -1; |
| for ( i = iFirstPo; i < iFirstPoNext; i++ ) |
| { |
| Delay = If_CutComputeDelay( pIfMan, pCut, pCanonPerm, Vec_WrdEntry(p->vDelays, i) ); |
| Area = Vec_StrEntry(p->vAreas, i); |
| if ( iBestPo == -1 || BestDelay > Delay || (BestDelay == Delay && BestArea > Area) ) |
| { |
| iBestPo = i; |
| BestDelay = Delay; |
| BestArea = Area; |
| } |
| } |
| if ( pBestPo ) |
| *pBestPo = iBestPo; |
| |
| // mark as user cut. |
| DelayProfile = Vec_WrdEntry(p->vDelays, iBestPo); |
| pCut->Cost = Vec_StrEntry(p->vAreas, iBestPo); |
| for ( i = 0; i < nLeaves; i++ ) |
| pPerm[(int)pCanonPerm[i]] = Lms_DelayGet(DelayProfile, i); |
| if ( 0 ) |
| { |
| int Max = 0, Two = 0, pTimes[16]; |
| for ( i = 0; i < nLeaves; i++ ) |
| pTimes[i] = (int)If_ObjCutBest(If_CutLeaf(pIfMan, pCut, i))->Delay; |
| for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) |
| Max = Abc_MaxInt( Max, pTimes[i] ); |
| for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) |
| if ( pTimes[i] != Max ) |
| Two = Abc_MaxInt( Two, pTimes[i] ); |
| if ( Two + 2 < Max && Max + 3 < BestDelay ) |
| { |
| for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) |
| printf( "%3d ", pTimes[i] ); |
| for ( ; i < pIfMan->pPars->nLutSize; i++ ) |
| printf( " " ); |
| printf( "-> %3d ", BestDelay ); |
| Dau_DsdPrintFromTruth( If_CutTruthW(pIfMan, pCut), If_CutLeaveNum(pCut) ); |
| } |
| } |
| return BestDelay; |
| } |
| int If_CutDelayRecCost3( If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pObj ) |
| { |
| Lms_Man_t * p = s_pMan3; |
| char pCanonPerm[LMS_VAR_MAX]; |
| unsigned uCanonPhase = 0; |
| // make sure the cut functions match the library |
| assert( p->nVars == (int)pCut->nLimit ); |
| // if this assertion fires, it means that LMS manager was used for library construction |
| // in this case, GIA has to be written out and the manager restarted as described above |
| assert( !p->fLibConstr ); |
| if ( p->vTruthPo == NULL ) |
| Lms_ManPrepare( p ); |
| // return the delay of the best structure |
| return If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, NULL ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reexpresses the best structure of the cut in the HOP manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Hop_Obj_t * Abc_RecToHop3( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj ) |
| { |
| Lms_Man_t * p = s_pMan3; |
| char pCanonPerm[LMS_VAR_MAX]; |
| unsigned uCanonPhase = 0; |
| Hop_Obj_t * pFan0, * pFan1, * pHopObj; |
| Gia_Man_t * pGia = p->pGia; |
| Gia_Obj_t * pGiaPo, * pGiaTemp = NULL; |
| int i, uSupport, BestPo = -1, nLeaves = If_CutLeaveNum(pCut); |
| assert( pIfMan->pPars->fCutMin == 1 ); |
| |
| // compute support |
| uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves ); |
| if ( uSupport == 0 ) |
| return Hop_NotCond( Hop_ManConst0(pMan), If_CutTruthIsCompl(pCut) ); |
| if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 ) |
| { |
| assert( Abc_TtSuppOnlyOne(uSupport) ); |
| return Hop_NotCond( Hop_IthVar(pMan, Abc_TtSuppFindFirst(uSupport)), If_CutTruthIsCompl(pCut) ); |
| } |
| assert( Gia_WordCountOnes(uSupport) == nLeaves ); |
| |
| // get the best output for this node |
| If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, &BestPo ); |
| assert( BestPo >= 0 ); |
| pGiaPo = Gia_ManCo( pGia, BestPo ); |
| // collect internal nodes into pGia->vTtNodes |
| if ( pGia->vTtNodes == NULL ) |
| pGia->vTtNodes = Vec_IntAlloc( 256 ); |
| assert( Gia_ObjIsAnd( Gia_ObjFanin0(pGiaPo) ) ); |
| Gia_ObjCollectInternal( pGia, Gia_ObjFanin0(pGiaPo) ); |
| assert( Vec_IntSize(pGia->vTtNodes) > 0 ); |
| |
| // collect HOP nodes for leaves |
| Vec_PtrClear( p->vLabelsP ); |
| for ( i = 0; i < nLeaves; i++ ) |
| Vec_PtrPush( p->vLabelsP, Hop_NotCond(Hop_IthVar(pMan, pCanonPerm[i]), (uCanonPhase >> i) & 1) ); |
| |
| // compute HOP nodes for internal nodes |
| Gia_ManForEachObjVec( pGia->vTtNodes, pGia, pGiaTemp, i ) |
| { |
| pGiaTemp->fMark0 = 0; // unmark node marked by Gia_ObjCollectInternal() |
| if ( Gia_ObjIsAnd(Gia_ObjFanin0(pGiaTemp)) ) |
| pFan0 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, Gia_ObjFanin0(pGiaTemp)) + nLeaves); |
| else |
| pFan0 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjCioId(Gia_ObjFanin0(pGiaTemp))); |
| pFan0 = Hop_NotCond(pFan0, Gia_ObjFaninC0(pGiaTemp)); |
| if ( Gia_ObjIsAnd(Gia_ObjFanin1(pGiaTemp)) ) |
| pFan1 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, Gia_ObjFanin1(pGiaTemp)) + nLeaves); |
| else |
| pFan1 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjCioId(Gia_ObjFanin1(pGiaTemp))); |
| pFan1 = Hop_NotCond(pFan1, Gia_ObjFaninC1(pGiaTemp)); |
| |
| pHopObj = Hop_And(pMan, pFan0, pFan1); |
| Vec_PtrPush(p->vLabelsP, pHopObj); |
| } |
| // get the final result |
| assert( Gia_ObjIsAnd(pGiaTemp) ); |
| pHopObj = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, pGiaTemp) + nLeaves); |
| // complement the result if needed |
| return Hop_NotCond( pHopObj, Gia_ObjFaninC0(pGiaPo) ^ ((uCanonPhase >> nLeaves) & 1) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reexpresses the best structure of the cut in the GIA manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_RecToGia3( Gia_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, Vec_Int_t * vLeaves, int fHash ) |
| { |
| Lms_Man_t * p = s_pMan3; |
| char pCanonPerm[LMS_VAR_MAX]; |
| unsigned uCanonPhase; |
| int iFan0, iFan1, iGiaObj; |
| Gia_Man_t * pGia = p->pGia; |
| Gia_Obj_t * pGiaPo, * pGiaTemp = NULL; |
| int i, uSupport, BestPo = -1, nLeaves = If_CutLeaveNum(pCut); |
| assert( pIfMan->pPars->fCutMin == 1 ); |
| assert( nLeaves == Vec_IntSize(vLeaves) ); |
| |
| // compute support |
| uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves ); |
| if ( uSupport == 0 ) |
| return Abc_LitNotCond( 0, If_CutTruthIsCompl(pCut) ); |
| if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 ) |
| { |
| assert( Abc_TtSuppOnlyOne(uSupport) ); |
| return Abc_LitNotCond( Vec_IntEntry(vLeaves, Abc_TtSuppFindFirst(uSupport)), If_CutTruthIsCompl(pCut) ); |
| } |
| assert( Gia_WordCountOnes(uSupport) == nLeaves ); |
| |
| // get the best output for this node |
| If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, &BestPo ); |
| assert( BestPo >= 0 ); |
| pGiaPo = Gia_ManCo( pGia, BestPo ); |
| |
| // collect internal nodes into pGia->vTtNodes |
| if ( pGia->vTtNodes == NULL ) |
| pGia->vTtNodes = Vec_IntAlloc( 256 ); |
| assert( Gia_ObjIsAnd( Gia_ObjFanin0(pGiaPo) ) ); |
| Gia_ObjCollectInternal( pGia, Gia_ObjFanin0(pGiaPo) ); |
| assert( Vec_IntSize(pGia->vTtNodes) > 0 ); |
| |
| // collect GIA nodes for leaves |
| Vec_IntClear( p->vLabels ); |
| for (i = 0; i < nLeaves; i++) |
| Vec_IntPush( p->vLabels, Abc_LitNotCond(Vec_IntEntry(vLeaves, pCanonPerm[i]), (uCanonPhase >> i) & 1) ); |
| |
| // compute HOP nodes for internal nodes |
| Gia_ManForEachObjVec( pGia->vTtNodes, pGia, pGiaTemp, i ) |
| { |
| pGiaTemp->fMark0 = 0; // unmark node marked by Gia_ObjCollectInternal() |
| if ( Gia_ObjIsAnd(Gia_ObjFanin0(pGiaTemp)) ) |
| iFan0 = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, Gia_ObjFanin0(pGiaTemp)) + nLeaves); |
| else |
| iFan0 = Vec_IntEntry(p->vLabels, Gia_ObjCioId(Gia_ObjFanin0(pGiaTemp))); |
| iFan0 = Abc_LitNotCond(iFan0, Gia_ObjFaninC0(pGiaTemp)); |
| if ( Gia_ObjIsAnd(Gia_ObjFanin1(pGiaTemp)) ) |
| iFan1 = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, Gia_ObjFanin1(pGiaTemp)) + nLeaves); |
| else |
| iFan1 = Vec_IntEntry(p->vLabels, Gia_ObjCioId(Gia_ObjFanin1(pGiaTemp))); |
| iFan1 = Abc_LitNotCond(iFan1, Gia_ObjFaninC1(pGiaTemp)); |
| if ( fHash ) |
| iGiaObj = Gia_ManHashAnd(pMan, iFan0, iFan1); |
| else |
| iGiaObj = Gia_ManAppendAnd(pMan, iFan0, iFan1); |
| Vec_IntPush(p->vLabels, iGiaObj); |
| } |
| // get the final result |
| assert( Gia_ObjIsAnd(pGiaTemp) ); |
| iGiaObj = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, pGiaTemp) + nLeaves); |
| // complement the result if needed |
| return Abc_LitNotCond( iGiaObj, Gia_ObjFaninC0(pGiaPo) ^ ((uCanonPhase >> nLeaves) & 1) ^ pCut->fCompl ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reduces GIA to contain only useful COs and internal nodes.] |
| |
| Description [During library construction, redundant nodes are added. |
| Some COs are found to be useless because their TT does not match the |
| (semi-canonicized TT) of the cut, etc. This procedure reduces GIA |
| to contains only useful (non-redundant, non-dominated) COs and the |
| corresponding internal nodes. This procedure replaces GIA by a new GIA |
| and creates new vTruthIds. The COs with the same truth table have |
| adjacent IDs. This procedure does not change the truth tables.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| // count how many times TT occurs |
| Vec_Int_t * Lms_GiaCountTruths( Lms_Man_t * p ) |
| { |
| Vec_Int_t * vCounts = Vec_IntStart( Vec_MemEntryNum(p->vTtMem) ); |
| int i, Entry; |
| Vec_IntForEachEntry( p->vTruthIds, Entry, i ) |
| if ( Entry >= 0 ) |
| Vec_IntAddToEntry( vCounts, Entry, 1 ); |
| return vCounts; |
| } |
| // collect PO indexes worth visiting |
| Vec_Int_t * Lms_GiaCollectUsefulCos( Lms_Man_t * p ) |
| { |
| Vec_Int_t * vBegins = Vec_IntAlloc( Vec_MemEntryNum(p->vTtMem) ); |
| Vec_Int_t * vUseful = Vec_IntStartFull( Gia_ManCoNum(p->pGia) + Vec_MemEntryNum(p->vTtMem) ); |
| Vec_Int_t * vCounts = Lms_GiaCountTruths( p ); |
| int i, Entry, * pPlace, SumTotal = 0; |
| // mark up the place for POs |
| Vec_IntForEachEntry( vCounts, Entry, i ) |
| { |
| assert( Entry > 0 ); |
| Vec_IntPush( vBegins, SumTotal ); |
| SumTotal += Entry + 1; |
| // printf( "%d ", Entry ); |
| } |
| Vec_IntPush( vBegins, SumTotal ); |
| // fill out POs in their places |
| Vec_IntFill( vCounts, Vec_IntSize(vCounts), 0 ); |
| Vec_IntForEachEntry( p->vTruthIds, Entry, i ) |
| { |
| if ( Entry < 0 ) |
| continue; |
| pPlace = Vec_IntEntryP( vUseful, Vec_IntEntry(vBegins, Entry) + Vec_IntEntry(vCounts, Entry) ); |
| assert( *pPlace == -1 ); |
| *pPlace = i; |
| Vec_IntAddToEntry( vCounts, Entry, 1 ); |
| } |
| Vec_IntFree( vBegins ); |
| Vec_IntFree( vCounts ); |
| return vUseful; |
| } |
| // collect non-dominated COs |
| Vec_Int_t * Lms_GiaFindNonRedundantCos( Lms_Man_t * p ) |
| { |
| Vec_Int_t * vRemain; |
| Vec_Int_t * vUseful; |
| Vec_Wrd_t * vDelays; |
| int i, k, EntryI, EntryK; |
| word D1, D2; |
| vDelays = Lms_GiaDelays( p->pGia ); |
| vUseful = Lms_GiaCollectUsefulCos( p ); |
| Vec_IntForEachEntry( vUseful, EntryI, i ) |
| { |
| if ( EntryI < 0 ) |
| continue; |
| D1 = Vec_WrdEntry(vDelays, EntryI); |
| assert( D1 > 0 ); |
| Vec_IntForEachEntryStart( vUseful, EntryK, k, i+1 ) |
| { |
| if ( EntryK == -1 ) |
| break; |
| if ( EntryK == -2 ) |
| continue; |
| D2 = Vec_WrdEntry(vDelays, EntryK); |
| assert( D2 > 0 ); |
| if ( Lms_DelayDom(D1, D2, Gia_ManCiNum(p->pGia)) ) // D1 dominate D2 |
| { |
| Vec_IntWriteEntry( vUseful, k, -2 ); |
| continue; |
| } |
| if ( Lms_DelayDom(D2, D1, Gia_ManCiNum(p->pGia)) ) // D2 dominate D1 |
| { |
| Vec_IntWriteEntry( vUseful, i, -2 ); |
| break; |
| } |
| } |
| } |
| |
| vRemain = Vec_IntAlloc( 1000 ); |
| Vec_IntForEachEntry( vUseful, EntryI, i ) |
| if ( EntryI >= 0 ) |
| Vec_IntPush( vRemain, EntryI ); |
| Vec_IntFree( vUseful ); |
| Vec_WrdFree( vDelays ); |
| return vRemain; |
| } |
| // replace GIA and vTruthIds by filtered ones |
| void Lms_GiaNormalize( Lms_Man_t * p ) |
| { |
| Gia_Man_t * pGiaNew; |
| Gia_Obj_t * pObj; |
| Vec_Int_t * vRemain; |
| Vec_Int_t * vTruthIdsNew; |
| int i, Entry, Prev = -1, Next; |
| // collect non-redundant COs |
| vRemain = Lms_GiaFindNonRedundantCos( p ); |
| // change these to be useful literals |
| vTruthIdsNew = Vec_IntAlloc( Vec_IntSize(vRemain) ); |
| Vec_IntForEachEntry( vRemain, Entry, i ) |
| { |
| pObj = Gia_ManCo(p->pGia, Entry); |
| assert( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) ); |
| Vec_IntWriteEntry( vRemain, i, Gia_ObjFaninLit0p(p->pGia, pObj) ); |
| // create new truth IDs |
| Next = Vec_IntEntry(p->vTruthIds, Gia_ObjCioId(pObj)); |
| assert( Prev <= Next ); |
| Vec_IntPush( vTruthIdsNew, Next ); |
| Prev = Next; |
| } |
| // create a new GIA |
| Gia_ManForEachObj( p->pGia, pObj, i ) |
| assert( pObj->fMark0 == 0 ); |
| for ( i = 0; i < Gia_ManCoNum(p->pGia); i++ ) |
| Gia_ManPatchCoDriver( p->pGia, i, 0 ); |
| Vec_IntForEachEntry( vRemain, Entry, i ) |
| Gia_ManAppendCo( p->pGia, Entry ); |
| // pGiaNew = Gia_ManCleanup( p->pGia ); |
| pGiaNew = Gia_ManCleanupOutputs( p->pGia, Gia_ManCoNum(p->pGia) - Vec_IntSize(vRemain) ); |
| Gia_ManStop( p->pGia ); |
| p->pGia = pGiaNew; |
| Vec_IntFree( vRemain ); |
| // update truth IDs |
| Vec_IntFree( p->vTruthIds ); |
| p->vTruthIds = vTruthIdsNew; |
| // Vec_IntPrint( vTruthIdsNew ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkRecTruthCompare( int * p1, int * p2 ) |
| { |
| int Diff = Vec_StrEntry( s_pMan3->vSupps, *p1 ) - Vec_StrEntry( s_pMan3->vSupps, *p2 ); |
| if ( Diff ) |
| return Diff; |
| return memcmp( Vec_MemReadEntry(s_pMan3->vTtMem, *p1), Vec_MemReadEntry(s_pMan3->vTtMem, *p2), sizeof(word) * s_pMan3->nWords ); |
| } |
| void Abc_NtkRecDumpTt3( char * pFileName, int fBinary ) |
| { |
| FILE * pFile; |
| char pBuffer[1000]; |
| Lms_Man_t * p = s_pMan3; |
| Vec_Int_t * vEntries; |
| word * pTruth; |
| int i, Entry, nVars = p->nVars; |
| int nEntries = Vec_MemEntryNum(p->vTtMem); |
| if ( nEntries == 0 ) |
| { |
| printf( "There is not truth tables.\n" ); |
| return; |
| } |
| pFile = fopen( pFileName, "wb" ); |
| if ( pFile == NULL ) |
| { |
| printf( "The file cannot be opened.\n" ); |
| return; |
| } |
| p->vSupps = Vec_StrAlloc( nEntries ); |
| Vec_MemForEachEntry( p->vTtMem, pTruth, i ) |
| Vec_StrPush( p->vSupps, (char)Abc_TtSupportSize(pTruth, nVars) ); |
| vEntries = Vec_IntStartNatural( nEntries ); |
| qsort( (void *)Vec_IntArray(vEntries), nEntries, sizeof(int), (int(*)(const void *,const void *))Abc_NtkRecTruthCompare ); |
| Vec_StrFreeP( &p->vSupps ); |
| // write the file |
| Vec_IntForEachEntry( vEntries, Entry, i ) |
| { |
| pTruth = Vec_MemReadEntry(p->vTtMem, Entry); |
| if ( fBinary ) |
| { |
| fwrite( pTruth, 1, sizeof(word) * p->nWords, pFile ); |
| continue; |
| } |
| Extra_PrintHex( pFile, (unsigned *)pTruth, nVars ); |
| fprintf( pFile, " " ); |
| // Kit_DsdWriteFromTruth( pBuffer, (unsigned *)pTruth, nVars ); |
| Dau_DsdDecompose( pTruth, p->nVars, 0, (int)(nVars <= 10), pBuffer ); |
| fprintf( pFile, "%s\n", pBuffer ); |
| } |
| fclose( pFile ); |
| Vec_IntFree( vEntries ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkRecInputNum3() |
| { |
| return Gia_ManCiNum(s_pMan3->pGia); |
| } |
| int Abc_NtkRecIsRunning3() |
| { |
| return s_pMan3 != NULL; |
| } |
| Gia_Man_t * Abc_NtkRecGetGia3() |
| { |
| abctime clk = Abc_Clock(); |
| printf( "Before normalizing: Library has %d classes and %d AIG subgraphs with %d AND nodes.\n", |
| Vec_MemEntryNum(s_pMan3->vTtMem), Gia_ManPoNum(s_pMan3->pGia), Gia_ManAndNum(s_pMan3->pGia) ); |
| Lms_GiaNormalize( s_pMan3 ); |
| printf( "After normalizing: Library has %d classes and %d AIG subgraphs with %d AND nodes.\n", |
| Vec_MemEntryNum(s_pMan3->vTtMem), Gia_ManPoNum(s_pMan3->pGia), Gia_ManAndNum(s_pMan3->pGia) ); |
| Abc_PrintTime( 1, "Normalization runtime", Abc_Clock() - clk ); |
| s_pMan3->fLibConstr = 0; |
| return s_pMan3->pGia; |
| } |
| void Abc_NtkRecPs3(int fPrintLib) |
| { |
| Lms_ManPrint( s_pMan3 ); |
| } |
| void Abc_NtkRecStart3( Gia_Man_t * p, int nVars, int nCuts, int fFuncOnly, int fVerbose ) |
| { |
| assert( s_pMan3 == NULL ); |
| s_pMan3 = Lms_ManStart( p, nVars, nCuts, fFuncOnly, fVerbose ); |
| } |
| |
| void Abc_NtkRecStop3() |
| { |
| assert( s_pMan3 != NULL ); |
| Lms_ManStop( s_pMan3 ); |
| s_pMan3 = NULL; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |