diff --git a/Makefile b/Makefile index eeff20d24..8a8058500 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ MODULES := \ src/base/abc src/base/abci src/base/cmd src/base/io src/base/main src/base/exor \ src/base/ver src/base/wlc src/base/wln src/base/acb src/base/bac src/base/cba src/base/pla src/base/test \ src/map/mapper src/map/mio src/map/super src/map/if src/map/if/acd \ - src/map/amap src/map/cov src/map/scl src/map/mpm \ + src/map/amap src/map/cov src/map/scl src/map/mpm src/map/emap \ src/misc/extra src/misc/mvc src/misc/st src/misc/util src/misc/nm \ src/misc/vec src/misc/hash src/misc/tim src/misc/bzlib src/misc/zlib \ src/misc/mem src/misc/bar src/misc/bbl src/misc/parse src/misc/btor \ @@ -185,32 +185,32 @@ DEP := $(OBJ:.o=.d) %.o: %.c @mkdir -p $(dir $@) @echo "$(MSG_PREFIX)\`\` Compiling:" $(LOCAL_PATH)/$< - $(VERBOSE)$(CC) -c $(OPTFLAGS) $(INCLUDES) $(CFLAGS) $< -o $@ + $(VERBOSE)$(CC) -c $(OPTFLAGS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $< -o $@ %.o: %.cc @mkdir -p $(dir $@) @echo "$(MSG_PREFIX)\`\` Compiling:" $(LOCAL_PATH)/$< - $(VERBOSE)$(CXX) -c $(OPTFLAGS) $(INCLUDES) $(CXXFLAGS) $< -o $@ + $(VERBOSE)$(CXX) -c $(OPTFLAGS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) $< -o $@ %.o: %.cpp @mkdir -p $(dir $@) @echo "$(MSG_PREFIX)\`\` Compiling:" $(LOCAL_PATH)/$< - $(VERBOSE)$(CXX) -c $(OPTFLAGS) $(INCLUDES) $(CXXFLAGS) $< -o $@ + $(VERBOSE)$(CXX) -c $(OPTFLAGS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) $< -o $@ %.d: %.c @mkdir -p $(dir $@) @echo "$(MSG_PREFIX)\`\` Generating dependency:" $(LOCAL_PATH)/$< - $(VERBOSE)$(ABCSRC)/depends.sh "$(CC)" `dirname $*.c` $(OPTFLAGS) $(INCLUDES) $(CFLAGS) $< > $@ + $(VERBOSE)$(ABCSRC)/depends.sh "$(CC)" `dirname $*.c` $(OPTFLAGS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $< > $@ %.d: %.cc @mkdir -p $(dir $@) @echo "$(MSG_PREFIX)\`\` Generating dependency:" $(LOCAL_PATH)/$< - $(VERBOSE)$(ABCSRC)/depends.sh "$(CXX)" `dirname $*.cc` $(OPTFLAGS) $(INCLUDES) $(CXXFLAGS) $< > $@ + $(VERBOSE)$(ABCSRC)/depends.sh "$(CXX)" `dirname $*.cc` $(OPTFLAGS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) $< > $@ %.d: %.cpp @mkdir -p $(dir $@) @echo "$(MSG_PREFIX)\`\` Generating dependency:" $(LOCAL_PATH)/$< - $(VERBOSE)$(ABCSRC)/depends.sh "$(CXX)" `dirname $*.cpp` $(OPTFLAGS) $(INCLUDES) $(CXXFLAGS) $< > $@ + $(VERBOSE)$(ABCSRC)/depends.sh "$(CXX)" `dirname $*.cpp` $(OPTFLAGS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) $< > $@ ifndef ABC_MAKE_NO_DEPS -include $(DEP) diff --git a/abclib.dsp b/abclib.dsp index d272b819e..2f16e849e 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -4801,6 +4801,22 @@ SOURCE=.\src\map\mpm\mpmTruth.c SOURCE=.\src\map\mpm\mpmUtil.c # End Source File # End Group +# Begin Group "emap" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\src\map\emap\emap.c +# End Source File +# Begin Source File + +SOURCE=.\src\map\emap\emap.h +# End Source File +# Begin Source File + +SOURCE=.\src\map\emap\emapCore.c +# End Source File +# End Group # End Group # Begin Group "misc" @@ -6665,6 +6681,10 @@ SOURCE=.\src\proof\cec\cecCorr.c # End Source File # Begin Source File +SOURCE=.\src\proof\cec\cecCorrIncr.c +# End Source File +# Begin Source File + SOURCE=.\src\proof\cec\cecInt.h # End Source File # Begin Source File diff --git a/src/aig/gia/giaAiger.c b/src/aig/gia/giaAiger.c index c37c3ea9e..c17783832 100644 --- a/src/aig/gia/giaAiger.c +++ b/src/aig/gia/giaAiger.c @@ -428,9 +428,6 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi } else if ( *pType == 'l' ) { - char Buffer[1000]; - assert( strlen(pName) < 995 ); - sprintf( Buffer, "%s_in", pName ); if ( vNamesRegIn == NULL ) vNamesRegIn = Vec_PtrStart( nLatches ); if ( vNamesRegOut == NULL ) @@ -440,7 +437,7 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi fError = 1; break; } - Vec_PtrWriteEntry( vNamesRegIn, iTerm, Abc_UtilStrsav(Buffer) ); + Vec_PtrWriteEntry( vNamesRegIn, iTerm, Abc_UtilStrsavTwo(pName, (char *)"_in") ); Vec_PtrWriteEntry( vNamesRegOut, iTerm, Abc_UtilStrsav(pName) ); } else if ( *pType == 'n' ) diff --git a/src/aig/gia/giaDup.c b/src/aig/gia/giaDup.c index d1187cb24..a29271605 100644 --- a/src/aig/gia/giaDup.c +++ b/src/aig/gia/giaDup.c @@ -6964,6 +6964,591 @@ void Gia_ManDupSplit( Gia_Man_t * p, int nParts, int nCutLevel ) Vec_PtrFreeFree( vCutNames ); } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Gia_ManDupPipelineMapPos( int nStages, int iObj, int iStage ) +{ + return iObj * nStages + iStage; +} + +static int Gia_ManDupPipelineDelayLit( Gia_Man_t * pNew, Vec_Int_t * vLitMap, Vec_Int_t * vStages, Vec_Int_t * vRegDrivers, Vec_Int_t * vRegStages, int nStages, int iObj, int iStage ) +{ + int iPos, iStageBase, iLitPrev, iLit; + if ( iObj == 0 ) + return 0; + iPos = Gia_ManDupPipelineMapPos( nStages, iObj, iStage ); + iLit = Vec_IntEntry( vLitMap, iPos ); + if ( iLit >= 0 ) + return iLit; + iStageBase = Vec_IntEntry( vStages, iObj ); + assert( iStage >= iStageBase ); + assert( iStage > 0 ); + iLitPrev = Gia_ManDupPipelineDelayLit( pNew, vLitMap, vStages, vRegDrivers, vRegStages, nStages, iObj, iStage - 1 ); + iLit = Gia_ManAppendCi( pNew ); + Vec_IntWriteEntry( vLitMap, iPos, iLit ); + Vec_IntPush( vRegDrivers, iLitPrev ); + Vec_IntPush( vRegStages, iStage - 1 ); + return iLit; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static char * Gia_ManDupPipelineNameCopy( Vec_Ptr_t * vNames, int iName, char * pPrefix, int i ) +{ + char * pName = (vNames && iName < Vec_PtrSize(vNames)) ? (char *)Vec_PtrEntry(vNames, iName) : NULL; + return pName ? Abc_UtilStrsav( pName ) : Abc_UtilStrsavNum( pPrefix, i ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Gia_Man_t * Gia_ManDupPipeline( Gia_Man_t * p, int nLevels, int fVerbose ) +{ + Gia_Man_t * pNew; + Gia_Obj_t * pObj; + Vec_Int_t * vStages, * vLitMap, * vRegDrivers, * vRegStages, * vStageCounts; + Vec_Ptr_t * vNamesIn, * vNamesOut; + char * pNameRo; + int nObjs, nLevelMax, nStageMax, nStageCols, i, iStage, iLit0, iLit1, iLit, iFlop; + + if ( nLevels <= 0 ) + return NULL; + if ( Gia_ManRegNum(p) > 0 ) + return NULL; + + Gia_ManLevelNum( p ); + nObjs = Gia_ManObjNum( p ); + nLevelMax = Gia_ManLevelNum( p ); + nStageMax = nLevelMax ? (nLevelMax - 1) / nLevels : 0; + nStageCols = nStageMax + 1; + + vStages = Vec_IntStart( nObjs ); + vLitMap = Vec_IntStartFull( nObjs * nStageCols ); + vRegDrivers = Vec_IntAlloc( 1000 ); + vRegStages = Vec_IntAlloc( 1000 ); + + Gia_ManForEachAnd( p, pObj, i ) + Vec_IntWriteEntry( vStages, Gia_ObjId(p, pObj), (Gia_ObjLevel(p, pObj) - 1) / nLevels ); + + pNew = Gia_ManStart( Gia_ManObjNum(p) + 2 * Gia_ManAndNum(p) ); + pNew->pName = Abc_UtilStrsav( p->pName ); + pNew->pSpec = Abc_UtilStrsav( p->pSpec ); + pNew->nConstrs = p->nConstrs; + Gia_ManHashAlloc( pNew ); + + Gia_ManForEachPi( p, pObj, i ) + { + iLit = Gia_ManAppendCi( pNew ); + Vec_IntWriteEntry( vLitMap, Gia_ManDupPipelineMapPos(nStageCols, Gia_ObjId(p, pObj), 0), iLit ); + } + + Gia_ManForEachAnd( p, pObj, i ) + { + iStage = Vec_IntEntry( vStages, Gia_ObjId(p, pObj) ); + iLit0 = Gia_ManDupPipelineDelayLit( pNew, vLitMap, vStages, vRegDrivers, vRegStages, nStageCols, Gia_ObjFaninId0p(p, pObj), iStage ); + iLit1 = Gia_ManDupPipelineDelayLit( pNew, vLitMap, vStages, vRegDrivers, vRegStages, nStageCols, Gia_ObjFaninId1p(p, pObj), iStage ); + iLit = Gia_ManHashAnd( pNew, Abc_LitNotCond(iLit0, Gia_ObjFaninC0(pObj)), Abc_LitNotCond(iLit1, Gia_ObjFaninC1(pObj)) ); + Vec_IntWriteEntry( vLitMap, Gia_ManDupPipelineMapPos(nStageCols, Gia_ObjId(p, pObj), iStage), iLit ); + } + + Gia_ManForEachPo( p, pObj, i ) + { + iLit = Gia_ManDupPipelineDelayLit( pNew, vLitMap, vStages, vRegDrivers, vRegStages, nStageCols, Gia_ObjFaninId0p(p, pObj), nStageMax ); + Gia_ManAppendCo( pNew, Abc_LitNotCond(iLit, Gia_ObjFaninC0(pObj)) ); + } + + Vec_IntForEachEntry( vRegDrivers, iLit, i ) + Gia_ManAppendCo( pNew, iLit ); + Gia_ManSetRegNum( pNew, Vec_IntSize(vRegDrivers) ); + + vNamesIn = Vec_PtrAlloc( Gia_ManCiNum(pNew) ); + vNamesOut = Vec_PtrAlloc( Gia_ManCoNum(pNew) ); + vStageCounts = Vec_IntStart( nStageCols ); + Gia_ManForEachPi( p, pObj, i ) + Vec_PtrPush( vNamesIn, Gia_ManDupPipelineNameCopy(p->vNamesIn, i, (char *)"pi", i) ); + Gia_ManForEachPo( p, pObj, i ) + Vec_PtrPush( vNamesOut, Gia_ManDupPipelineNameCopy(p->vNamesOut, i, (char *)"po", i) ); + Vec_IntForEachEntry( vRegStages, iStage, i ) + { + char Buffer[64], BufferIn[64]; + iFlop = Vec_IntEntry( vStageCounts, iStage ); + Vec_IntWriteEntry( vStageCounts, iStage, iFlop + 1 ); + snprintf( Buffer, sizeof(Buffer), "cut%d[%d]", iStage, iFlop ); + snprintf( BufferIn, sizeof(BufferIn), "cut%d_in[%d]", iStage, iFlop ); + pNameRo = Abc_UtilStrsav( Buffer ); + Vec_PtrPush( vNamesIn, pNameRo ); + Vec_PtrPush( vNamesOut, Abc_UtilStrsav( BufferIn ) ); + } + pNew->vNamesIn = vNamesIn; + pNew->vNamesOut = vNamesOut; + Gia_ManHashStop( pNew ); + + if ( fVerbose ) + Abc_Print( 1, "Inserted %d fixed-cut pipeline registers using D = %d.\n", Gia_ManRegNum(pNew), nLevels ); + + Vec_IntFree( vStages ); + Vec_IntFree( vLitMap ); + Vec_IntFree( vRegDrivers ); + Vec_IntFree( vRegStages ); + Vec_IntFree( vStageCounts ); + return pNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static Vec_Ptr_t * Gia_ManDupUnpipelineNames( Vec_Ptr_t * vNames, int nNames ) +{ + Vec_Ptr_t * vRes; + char * pName; + int i; + if ( vNames == NULL ) + return NULL; + vRes = Vec_PtrAlloc( nNames ); + for ( i = 0; i < nNames; i++ ) + { + pName = i < Vec_PtrSize(vNames) ? (char *)Vec_PtrEntry( vNames, i ) : NULL; + Vec_PtrPush( vRes, pName ? Abc_UtilStrsav(pName) : NULL ); + } + return vRes; +} + +/**Function************************************************************* + + Synopsis [Duplicates selected names if present.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static Vec_Ptr_t * Gia_ManDupUnpipelineNamesUsed( Vec_Ptr_t * vNames, Vec_Bit_t * vUsed, int nNames ) +{ + Vec_Ptr_t * vRes; + char * pName; + int i; + if ( vNames == NULL ) + return NULL; + vRes = Vec_PtrAlloc( Vec_BitCount(vUsed) ); + for ( i = 0; i < nNames; i++ ) + { + if ( !Vec_BitEntry(vUsed, i) ) + continue; + pName = i < Vec_PtrSize(vNames) ? (char *)Vec_PtrEntry( vNames, i ) : NULL; + Vec_PtrPush( vRes, pName ? Abc_UtilStrsav(pName) : NULL ); + } + return vRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Gia_ManDupUnpipeline_rec( Gia_Man_t * pNew, Gia_Man_t * p, Vec_Int_t * vCopies, int iObj, int * piCycle ) +{ + Gia_Obj_t * pObj = Gia_ManObj( p, iObj ); + int iLit, iLit0, iLit1; + + iLit = Vec_IntEntry( vCopies, iObj ); + if ( iLit >= 0 ) + return iLit; + if ( iLit == -2 ) + { + if ( piCycle ) + *piCycle = iObj; + return -1; + } + Vec_IntWriteEntry( vCopies, iObj, -2 ); + + if ( !p->fGiaSimple && Gia_ObjIsBuf(pObj) ) + { + iLit0 = Gia_ManDupUnpipeline_rec( pNew, p, vCopies, Gia_ObjFaninId0p(p, pObj), piCycle ); + if ( iLit0 < 0 ) + return -1; + iLit = Abc_LitNotCond( iLit0, Gia_ObjFaninC0(pObj) ); + } + else if ( Gia_ObjIsAnd(pObj) ) + { + iLit0 = Gia_ManDupUnpipeline_rec( pNew, p, vCopies, Gia_ObjFaninId0p(p, pObj), piCycle ); + if ( iLit0 < 0 ) + return -1; + iLit1 = Gia_ManDupUnpipeline_rec( pNew, p, vCopies, Gia_ObjFaninId1p(p, pObj), piCycle ); + if ( iLit1 < 0 ) + return -1; + iLit = Gia_ManHashAnd( pNew, Abc_LitNotCond(iLit0, Gia_ObjFaninC0(pObj)), Abc_LitNotCond(iLit1, Gia_ObjFaninC1(pObj)) ); + } + else if ( Gia_ObjIsRo(p, pObj) ) + { + Gia_Obj_t * pObjRi = Gia_ObjRoToRi( p, pObj ); + iLit0 = Gia_ManDupUnpipeline_rec( pNew, p, vCopies, Gia_ObjFaninId0p(p, pObjRi), piCycle ); + if ( iLit0 < 0 ) + return -1; + iLit = Abc_LitNotCond( iLit0, Gia_ObjFaninC0(pObjRi) ); + } + else + { + assert( 0 ); + return -1; + } + + Vec_IntWriteEntry( vCopies, iObj, iLit ); + return iLit; +} + +/**Function************************************************************* + + Synopsis [Marks objects reachable after bypassing flops.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Gia_ManDupUnpipelineMark_rec( Gia_Man_t * p, Vec_Str_t * vMarks, Vec_Bit_t * vPisUsed, int iObj, int * piCycle ) +{ + Gia_Obj_t * pObj = Gia_ManObj( p, iObj ); + int Mark = Vec_StrEntry( vMarks, iObj ); + if ( Mark == 2 ) + return 0; + if ( Mark == 1 ) + { + if ( piCycle ) + *piCycle = iObj; + return -1; + } + if ( Gia_ObjIsConst0(pObj) ) + { + Vec_StrWriteEntry( vMarks, iObj, 2 ); + return 0; + } + if ( Gia_ObjIsPi(p, pObj) ) + { + Vec_BitWriteEntry( vPisUsed, Gia_ObjCioId(pObj), 1 ); + Vec_StrWriteEntry( vMarks, iObj, 2 ); + return 0; + } + + Vec_StrWriteEntry( vMarks, iObj, 1 ); + if ( !p->fGiaSimple && Gia_ObjIsBuf(pObj) ) + { + if ( Gia_ManDupUnpipelineMark_rec( p, vMarks, vPisUsed, Gia_ObjFaninId0p(p, pObj), piCycle ) < 0 ) + return -1; + } + else if ( Gia_ObjIsAnd(pObj) ) + { + if ( Gia_ManDupUnpipelineMark_rec( p, vMarks, vPisUsed, Gia_ObjFaninId0p(p, pObj), piCycle ) < 0 ) + return -1; + if ( Gia_ManDupUnpipelineMark_rec( p, vMarks, vPisUsed, Gia_ObjFaninId1p(p, pObj), piCycle ) < 0 ) + return -1; + } + else if ( Gia_ObjIsRo(p, pObj) ) + { + Gia_Obj_t * pObjRi = Gia_ObjRoToRi( p, pObj ); + if ( Gia_ManDupUnpipelineMark_rec( p, vMarks, vPisUsed, Gia_ObjFaninId0p(p, pObjRi), piCycle ) < 0 ) + return -1; + } + else + { + assert( 0 ); + return -1; + } + Vec_StrWriteEntry( vMarks, iObj, 2 ); + return 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Gia_Man_t * Gia_ManDupUnpipeline( Gia_Man_t * p, int fVerbose ) +{ + Gia_Man_t * pNew; + Gia_Obj_t * pObj; + Vec_Bit_t * vPisUsed; + Vec_Int_t * vCopies; + Vec_Str_t * vMarks; + int i, iLit, iCycle = -1, nRegs, nPisUsed = 0; + + if ( Gia_ManRegNum(p) == 0 ) + return Gia_ManDup( p ); + + nRegs = Gia_ManRegNum( p ); + vPisUsed = Vec_BitStart( Gia_ManPiNum(p) ); + vMarks = Vec_StrStart( Gia_ManObjNum(p) ); + Gia_ManForEachPo( p, pObj, i ) + if ( Gia_ManDupUnpipelineMark_rec( p, vMarks, vPisUsed, Gia_ObjFaninId0p(p, pObj), &iCycle ) < 0 ) + break; + Vec_StrFree( vMarks ); + if ( iCycle >= 0 ) + { + if ( fVerbose ) + Abc_Print( 1, "Bypassing flops creates a combinational cycle at object %d.\n", iCycle ); + Vec_BitFree( vPisUsed ); + return NULL; + } + + vCopies = Vec_IntStartFull( Gia_ManObjNum(p) ); + Vec_IntWriteEntry( vCopies, 0, 0 ); + + pNew = Gia_ManStart( Gia_ManObjNum(p) ); + pNew->pName = Abc_UtilStrsav( p->pName ); + pNew->pSpec = Abc_UtilStrsav( p->pSpec ); + pNew->nConstrs = p->nConstrs; + pNew->vNamesIn = Gia_ManDupUnpipelineNamesUsed( p->vNamesIn, vPisUsed, Gia_ManPiNum(p) ); + pNew->vNamesOut = Gia_ManDupUnpipelineNames( p->vNamesOut, Gia_ManPoNum(p) ); + Gia_ManHashAlloc( pNew ); + + Gia_ManForEachPi( p, pObj, i ) + if ( Vec_BitEntry(vPisUsed, i) ) + { + Vec_IntWriteEntry( vCopies, Gia_ObjId(p, pObj), Gia_ManAppendCi(pNew) ); + nPisUsed++; + } + + Gia_ManForEachPo( p, pObj, i ) + { + iLit = Gia_ManDupUnpipeline_rec( pNew, p, vCopies, Gia_ObjFaninId0p(p, pObj), &iCycle ); + if ( iLit < 0 ) + break; + Gia_ManAppendCo( pNew, Abc_LitNotCond(iLit, Gia_ObjFaninC0(pObj)) ); + } + Gia_ManHashStop( pNew ); + Vec_IntFree( vCopies ); + Vec_BitFree( vPisUsed ); + + Gia_ManSetRegNum( pNew, 0 ); + if ( fVerbose ) + Abc_Print( 1, "Removed %d pipeline registers and kept %d primary inputs.\n", nRegs, nPisUsed ); + return pNew; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static char * Gia_ManDupRegioNameCopy( Vec_Ptr_t * vNames, int iName ) +{ + char * pName = (vNames && iName < Vec_PtrSize(vNames)) ? (char *)Vec_PtrEntry(vNames, iName) : NULL; + return pName ? Abc_UtilStrsav(pName) : NULL; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static char * Gia_ManDupRegioNameNew( Vec_Ptr_t * vNames, int iName, char * pSuffix, char * pPrefix, int i ) +{ + char * pName = (vNames && iName < Vec_PtrSize(vNames)) ? (char *)Vec_PtrEntry(vNames, iName) : NULL; + return pName ? Abc_UtilStrsavTwo( pName, pSuffix ) : Abc_UtilStrsavNum( pPrefix, i ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Gia_Man_t * Gia_ManDupRegio( Gia_Man_t * p, int fRegIns, int fRegOuts, int fVerbose ) +{ + Gia_Man_t * pNew; + Gia_Obj_t * pObj; + Vec_Int_t * vInRos = NULL, * vOutRos = NULL; + Vec_Ptr_t * vNamesIn = NULL, * vNamesOut = NULL; + int nPis = Gia_ManPiNum(p), nPos = Gia_ManPoNum(p), nRegs = Gia_ManRegNum(p); + int nRegIns = fRegIns ? nPis : 0; + int nRegOuts = fRegOuts ? nPos : 0; + int nRegsNew = nRegs + nRegIns + nRegOuts; + int i; + + if ( !fRegIns && !fRegOuts ) + return Gia_ManDup( p ); + + pNew = Gia_ManStart( Gia_ManObjNum(p) + 2 * (nRegIns + nRegOuts) ); + pNew->pName = Abc_UtilStrsav( p->pName ); + pNew->pSpec = Abc_UtilStrsav( p->pSpec ); + pNew->nConstrs = p->nConstrs; + + if ( p->vRegClasses ) + { + pNew->vRegClasses = Vec_IntAlloc( nRegsNew ); + for ( i = 0; i < nRegs; i++ ) + Vec_IntPush( pNew->vRegClasses, Vec_IntEntry(p->vRegClasses, i) ); + for ( ; i < nRegsNew; i++ ) + Vec_IntPush( pNew->vRegClasses, 0 ); + } + if ( p->vFlopClasses ) + { + pNew->vFlopClasses = Vec_IntAlloc( nRegsNew ); + for ( i = 0; i < nRegs; i++ ) + Vec_IntPush( pNew->vFlopClasses, Vec_IntEntry(p->vFlopClasses, i) ); + for ( ; i < nRegsNew; i++ ) + Vec_IntPush( pNew->vFlopClasses, 0 ); + } + if ( p->vRegInits ) + { + pNew->vRegInits = Vec_IntAlloc( nRegsNew ); + for ( i = 0; i < nRegs; i++ ) + Vec_IntPush( pNew->vRegInits, Vec_IntEntry(p->vRegInits, i) ); + for ( ; i < nRegsNew; i++ ) + Vec_IntPush( pNew->vRegInits, 0 ); + } + + if ( p->vNamesIn ) + { + vNamesIn = Vec_PtrAlloc( nPis + nRegsNew ); + for ( i = 0; i < nPis; i++ ) + Vec_PtrPush( vNamesIn, Gia_ManDupRegioNameCopy(p->vNamesIn, i) ); + for ( i = 0; i < nRegs; i++ ) + Vec_PtrPush( vNamesIn, Gia_ManDupRegioNameCopy(p->vNamesIn, nPis + i) ); + if ( fRegIns ) + for ( i = 0; i < nPis; i++ ) + Vec_PtrPush( vNamesIn, Gia_ManDupRegioNameNew(p->vNamesIn, i, (char *)"_i_ro", (char *)"inro", i) ); + if ( fRegOuts ) + for ( i = 0; i < nPos; i++ ) + Vec_PtrPush( vNamesIn, Gia_ManDupRegioNameNew(p->vNamesOut, i, (char *)"_o_ro", (char *)"outro", i) ); + pNew->vNamesIn = vNamesIn; + } + if ( p->vNamesOut ) + { + vNamesOut = Vec_PtrAlloc( nPos + nRegsNew ); + for ( i = 0; i < nPos; i++ ) + Vec_PtrPush( vNamesOut, Gia_ManDupRegioNameCopy(p->vNamesOut, i) ); + for ( i = 0; i < nRegs; i++ ) + Vec_PtrPush( vNamesOut, Gia_ManDupRegioNameCopy(p->vNamesOut, nPos + i) ); + if ( fRegIns ) + for ( i = 0; i < nPis; i++ ) + Vec_PtrPush( vNamesOut, Gia_ManDupRegioNameNew(p->vNamesIn, i, (char *)"_i_ri", (char *)"inri", i) ); + if ( fRegOuts ) + for ( i = 0; i < nPos; i++ ) + Vec_PtrPush( vNamesOut, Gia_ManDupRegioNameNew(p->vNamesOut, i, (char *)"_o_ri", (char *)"outri", i) ); + pNew->vNamesOut = vNamesOut; + } + + Gia_ManConst0(p)->Value = 0; + Gia_ManForEachPi( p, pObj, i ) + pObj->Value = Gia_ManAppendCi( pNew ); + Gia_ManForEachRo( p, pObj, i ) + pObj->Value = Gia_ManAppendCi( pNew ); + + if ( fRegIns ) + { + vInRos = Vec_IntAlloc( nPis ); + Gia_ManForEachPi( p, pObj, i ) + Vec_IntPush( vInRos, Gia_ManAppendCi( pNew ) ); + Gia_ManForEachPi( p, pObj, i ) + pObj->Value = Vec_IntEntry( vInRos, i ); + } + if ( fRegOuts ) + { + vOutRos = Vec_IntAlloc( nPos ); + for ( i = 0; i < nPos; i++ ) + Vec_IntPush( vOutRos, Gia_ManAppendCi( pNew ) ); + } + + Gia_ManForEachObj1( p, pObj, i ) + { + if ( !p->fGiaSimple && Gia_ObjIsBuf(pObj) ) + pObj->Value = Gia_ManAppendBuf( pNew, Gia_ObjFanin0Copy(pObj) ); + else if ( Gia_ObjIsAnd(pObj) ) + pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + } + + Gia_ManForEachPo( p, pObj, i ) + { + if ( fRegOuts ) + Gia_ManAppendCo( pNew, Vec_IntEntry(vOutRos, i) ); + else + Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) ); + } + Gia_ManForEachRi( p, pObj, i ) + Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) ); + if ( fRegIns ) + for ( i = 0; i < nPis; i++ ) + Gia_ManAppendCo( pNew, Gia_ManCiLit(pNew, i) ); + if ( fRegOuts ) + Gia_ManForEachPo( p, pObj, i ) + Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) ); + + Gia_ManSetRegNum( pNew, nRegsNew ); + Vec_IntFreeP( &vInRos ); + Vec_IntFreeP( &vOutRos ); + + if ( fVerbose ) + Abc_Print( 1, "Added %d input flops and %d output flops (total regs = %d).\n", nRegIns, nRegOuts, nRegsNew ); + return pNew; +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index c2d8886c0..1dd312843 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -3010,9 +3010,19 @@ Gia_Man_t * Gia_ManPerformMappingInt( Gia_Man_t * p, If_Par_t * pPars ) if ( p->pManTime && pPars->pTimesReq == NULL ) { Tim_Man_t * pManTime = (Tim_Man_t *)p->pManTime; - pPars->pTimesReq = ABC_CALLOC( float, Gia_ManCoNum(p) ); + int fHasFiniteReq = 0; for ( i = 0; i < Gia_ManCoNum(p); i++ ) - pPars->pTimesReq[i] = Tim_ManGetCoRequired( pManTime, i ); + if ( Tim_ManGetCoRequired( pManTime, i ) < TIM_ETERNITY ) + { + fHasFiniteReq = 1; + break; + } + if ( fHasFiniteReq ) + { + pPars->pTimesReq = ABC_CALLOC( float, Gia_ManCoNum(p) ); + for ( i = 0; i < Gia_ManCoNum(p); i++ ) + pPars->pTimesReq[i] = Tim_ManGetCoRequired( pManTime, i ); + } } ABC_FREE( p->pCellStr ); Vec_IntFreeP( &p->vConfigs ); diff --git a/src/base/abc/abcHieGia.c b/src/base/abc/abcHieGia.c index ea3c2d09a..bb35e7f0e 100644 --- a/src/base/abc/abcHieGia.c +++ b/src/base/abc/abcHieGia.c @@ -686,6 +686,32 @@ static Vec_Int_t * GiaHie_CountSymbsAll( Vec_Ptr_t * vNames ) } return vArray; } +static Vec_Int_t * GiaHie_CountSymbsSome( Vec_Ptr_t * vNames, int nNames ) +{ + char * pNameLast, * pName; + int i, nSymbsLast; + Vec_Int_t * vArray; + assert( vNames != NULL ); + assert( nNames >= 0 && nNames <= Vec_PtrSize(vNames) ); + if ( nNames == 0 ) + return Vec_IntAlloc( 0 ); + pNameLast = (char *)Vec_PtrEntry( vNames, 0 ); + nSymbsLast = GiaHie_CountSymbs( pNameLast ); + vArray = Vec_IntAlloc( nNames * 2 ); + Vec_IntPush( vArray, 0 ); + Vec_IntPush( vArray, nSymbsLast ); + for ( i = 1; i < nNames; i++ ) + { + pName = (char *)Vec_PtrEntry( vNames, i ); + if ( GiaHie_CountSymbs(pName) == nSymbsLast && !strncmp(pName, pNameLast, nSymbsLast) ) + continue; + nSymbsLast = GiaHie_CountSymbs( pName ); + Vec_IntPush( vArray, i ); + Vec_IntPush( vArray, nSymbsLast ); + pNameLast = pName; + } + return vArray; +} static void GiaHie_DumpIoList( Gia_Man_t * p, FILE * pFile, int fOuts, int fReverse ) { Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn; @@ -1013,6 +1039,88 @@ static int GiaHie_IsBitLevelNames( Vec_Ptr_t * vNames ) Vec_IntFree( vArray ); return 1; } +static int GiaHie_IsBitLevelNamesSome( Vec_Ptr_t * vNames, int nNames ) +{ + int nGroups, idx; + Vec_Int_t * vArray; + if ( vNames == NULL ) + return 1; + if ( nNames == 0 ) + return 1; + vArray = GiaHie_CountSymbsSome( vNames, nNames ); + nGroups = Vec_IntSize(vArray) / 2; + for ( idx = 0; idx < nGroups; idx++ ) + { + int iName = Vec_IntEntry( vArray, 2*idx ); + int iNameNext = (idx + 1 < nGroups) ? Vec_IntEntry(vArray, 2*(idx + 1)) : nNames; + if ( iNameNext - iName > 1 ) + { + Vec_IntFree( vArray ); + return 0; + } + } + Vec_IntFree( vArray ); + return 1; +} +static void GiaHie_DumpPortDeclsOneSome( Vec_Ptr_t * vNames, int nBits, FILE * pFile, int fOuts, int * pfFirst ) +{ + int fUsePiPo = (nBits > 2) && GiaHie_IsBitLevelNamesSome( vNames, nBits ); + if ( nBits == 0 ) + return; + if ( fUsePiPo ) + { + int nDigits = Abc_Base10Log( nBits ); + if ( nDigits < 2 ) + nDigits = 2; + if ( !(*pfFirst) ) + fprintf( pFile, ",\n" ); + fprintf( pFile, " %s ", fOuts ? "output" : "input" ); + GiaHie_WritePiPoNames( pFile, fOuts ? "po" : "pi", nBits, nDigits, 8, 4, 0 ); + *pfFirst = 0; + return; + } + if ( vNames == NULL ) + { + if ( !(*pfFirst) ) + fprintf( pFile, ",\n" ); + fprintf( pFile, " %s [%d:0] _%c_", fOuts ? "output" : "input", nBits-1, fOuts ? 'o' : 'i' ); + *pfFirst = 0; + return; + } + { + Vec_Int_t * vArray = GiaHie_CountSymbsSome( vNames, nBits ); + int iName, Size, i; + Vec_IntForEachEntryDouble( vArray, iName, Size, i ) + { + int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : nBits; + char * pName = (char *)Vec_PtrEntry(vNames, iName); + char * pNameLast = (char *)Vec_PtrEntry(vNames, iNameNext-1); + int NumBeg, NumEnd; + assert( !strncmp(pName, pNameLast, Size) ); + NumBeg = GiaHie_ReadRangeNum( pName, Size ); + NumEnd = GiaHie_ReadRangeNum( pNameLast, Size ); + if ( !(*pfFirst) ) + fprintf( pFile, ",\n" ); + fprintf( pFile, " %s ", fOuts ? "output" : "input" ); + if ( NumBeg != -1 && iName < iNameNext-1 ) + fprintf( pFile, "[%d:%d] ", NumEnd, NumBeg ); + GiaHie_PrintOneName( pFile, pName, Size ); + *pfFirst = 0; + } + Vec_IntFree( vArray ); + } +} +static void GiaHie_DumpPortDeclsSeq( Gia_Man_t * p, FILE * pFile, int fUseCtrlPis ) +{ + int fFirst = fUseCtrlPis ? 1 : 0; + if ( !fUseCtrlPis ) + { + fprintf( pFile, " input clk,\n" ); + fprintf( pFile, " input rst" ); + } + GiaHie_DumpPortDeclsOneSome( p->vNamesIn, Gia_ManPiNum(p), pFile, 0, &fFirst ); + GiaHie_DumpPortDeclsOneSome( p->vNamesOut, Gia_ManPoNum(p), pFile, 1, &fFirst ); +} static void GiaHie_DumpPortDeclsOne( Gia_Man_t * p, FILE * pFile, int fOuts, int * pfFirst ) { Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn; @@ -1205,6 +1313,224 @@ static void GiaHie_DumpOutputAssigns( Gia_Man_t * p, FILE * pFile, int nDigits ) Vec_IntFree( vArray ); } } +static void GiaHie_DumpInputAssignsSome( Gia_Man_t * p, FILE * pFile, int nDigits, int nCis ) +{ + Vec_Ptr_t * vNames = p->vNamesIn; + int fUsePiPo = (nCis > 2) && GiaHie_IsBitLevelNamesSome( vNames, nCis ); + if ( nCis == 0 ) + return; + if ( fUsePiPo ) + { + int nDigitsPi = Abc_Base10Log( nCis ); + if ( nDigitsPi < 2 ) + nDigitsPi = 2; + fprintf( pFile, " assign { " ); + GiaHie_WriteObjRange( pFile, p, 0, nCis, nDigits, 11, 4, 1, 1 ); + fprintf( pFile, " } =\n { " ); + GiaHie_WritePiPoNames( pFile, "pi", nCis, nDigitsPi, 18, 4, 1 ); + fprintf( pFile, " };\n" ); + return; + } + if ( vNames == NULL ) + { + if ( nCis == 1 ) + { + fprintf( pFile, " assign " ); + GiaHie_PrintObjName( pFile, Gia_ManCiIdToId(p, 0), nDigits ); + fprintf( pFile, " = _i_;\n" ); + } + else + { + fprintf( pFile, " assign { " ); + GiaHie_WriteObjRange( pFile, p, 0, nCis, nDigits, 11, 4, 1, 1 ); + fprintf( pFile, " } = { _i_ };\n" ); + } + return; + } + { + Vec_Int_t * vArray = GiaHie_CountSymbsSome( vNames, nCis ); + int iName, Size, i; + Vec_IntForEachEntryDouble( vArray, iName, Size, i ) + { + int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : nCis; + int nBits = iNameNext - iName; + char * pName = (char *)Vec_PtrEntry(vNames, iName); + if ( nBits > 1 ) + { + fprintf( pFile, " assign { " ); + GiaHie_WriteObjRange( pFile, p, iName, iNameNext, nDigits, 11, 4, 1, 1 ); + fprintf( pFile, " } =\n { " ); + GiaHie_PrintOneName( pFile, pName, Size ); + fprintf( pFile, " };\n" ); + } + else + { + fprintf( pFile, " assign " ); + GiaHie_PrintObjName( pFile, Gia_ManCiIdToId(p, iName), nDigits ); + fprintf( pFile, " = " ); + GiaHie_PrintOneName( pFile, pName, Size ); + fprintf( pFile, ";\n" ); + } + } + Vec_IntFree( vArray ); + } +} +static void GiaHie_DumpOutputAssignsSome( Gia_Man_t * p, FILE * pFile, int nDigits, int nCos ) +{ + Vec_Ptr_t * vNames = p->vNamesOut; + int fUsePiPo = (nCos > 2) && GiaHie_IsBitLevelNamesSome( vNames, nCos ); + if ( nCos == 0 ) + return; + if ( fUsePiPo ) + { + int nDigitsPo = Abc_Base10Log( nCos ); + if ( nDigitsPo < 2 ) + nDigitsPo = 2; + fprintf( pFile, " assign { " ); + GiaHie_WritePiPoNames( pFile, "po", nCos, nDigitsPo, 11, 4, 1 ); + fprintf( pFile, " } =\n { " ); + GiaHie_WriteObjRange( pFile, p, 0, nCos, nDigits, 18, 4, 1, 0 ); + fprintf( pFile, " };\n" ); + return; + } + if ( vNames == NULL ) + { + if ( nCos == 1 ) + { + fprintf( pFile, " assign _o_ = " ); + GiaHie_PrintObjName( pFile, Gia_ManCoIdToId(p, 0), nDigits ); + fprintf( pFile, ";\n" ); + } + else + { + fprintf( pFile, " assign { _o_ } = { " ); + GiaHie_WriteObjRange( pFile, p, 0, nCos, nDigits, 18, 4, 1, 0 ); + fprintf( pFile, " };\n" ); + } + return; + } + { + Vec_Int_t * vArray = GiaHie_CountSymbsSome( vNames, nCos ); + int iName, Size, i; + Vec_IntForEachEntryDouble( vArray, iName, Size, i ) + { + int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : nCos; + int nBits = iNameNext - iName; + char * pName = (char *)Vec_PtrEntry(vNames, iName); + if ( nBits > 1 ) + { + fprintf( pFile, " assign { " ); + GiaHie_PrintOneName( pFile, pName, Size ); + fprintf( pFile, " } =\n { " ); + GiaHie_WriteObjRange( pFile, p, iName, iNameNext, nDigits, 18, 4, 1, 0 ); + fprintf( pFile, " };\n" ); + } + else + { + fprintf( pFile, " assign " ); + GiaHie_PrintOneName( pFile, pName, Size ); + fprintf( pFile, " = " ); + GiaHie_PrintObjName( pFile, Gia_ManCoIdToId(p, iName), nDigits ); + fprintf( pFile, ";\n" ); + } + } + Vec_IntFree( vArray ); + } +} +static void GiaHie_DumpInterfaceAssignsSeq( Gia_Man_t * p, char * pFileName, int fUseCtrlPis ) +{ + Gia_Obj_t * pObj, * pObjRi, * pObjRo; + int nDigits = Abc_Base10Log( Gia_ManObjNum(p) ); + int nPerLine = 4, nOnLine = 0; + int i; + FILE * pFile; + if ( fUseCtrlPis && Gia_ManPiNum(p) < 2 ) + { + printf( "Sequential Verilog with \"-c\" expects at least 2 primary inputs.\n" ); + return; + } + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + { + printf( "Cannot open output file \"%s\".\n", pFileName ); + return; + } + + fprintf( pFile, "module " ); + GiaHie_DumpModuleName( pFile, p->pName ); + fprintf( pFile, " (\n" ); + GiaHie_DumpPortDeclsSeq( p, pFile, fUseCtrlPis ); + fprintf( pFile, "\n);\n\n" ); + + if ( Gia_ManPiNum(p) ) + { + fprintf( pFile, " wire " ); + GiaHie_WriteObjRange( pFile, p, 0, Gia_ManPiNum(p), nDigits, 7, 4, 0, 1 ); + fprintf( pFile, ";\n\n" ); + GiaHie_DumpInputAssignsSome( p, pFile, nDigits, Gia_ManPiNum(p) ); + fprintf( pFile, "\n" ); + } + if ( Gia_ManCoNum(p) ) + { + fprintf( pFile, " wire " ); + GiaHie_WriteObjRange( pFile, p, 0, Gia_ManCoNum(p), nDigits, 7, 4, 0, 0 ); + fprintf( pFile, ";\n\n" ); + } + if ( Gia_ManRegNum(p) ) + { + fprintf( pFile, " reg " ); + GiaHie_WriteObjRange( pFile, p, Gia_ManPiNum(p), Gia_ManCiNum(p), nDigits, 7, 4, 0, 1 ); + fprintf( pFile, ";\n\n" ); + } + + if ( GiaHie_ConstUsed(p) ) + fprintf( pFile, " wire n%0*d = 1'b0;\n\n", nDigits, 0 ); + + Gia_ManForEachAnd( p, pObj, i ) + { + if ( nOnLine == 0 ) + fprintf( pFile, " " ); + fprintf( pFile, "wire n%0*d = ", nDigits, i ); + GiaHie_PrintObjLit( pFile, Gia_ObjFaninId0(pObj, i), Gia_ObjFaninC0(pObj), nDigits ); + fprintf( pFile, " & " ); + GiaHie_PrintObjLit( pFile, Gia_ObjFaninId1(pObj, i), Gia_ObjFaninC1(pObj), nDigits ); + fprintf( pFile, "; " ); + nOnLine++; + if ( nOnLine == nPerLine ) + { + fprintf( pFile, "\n" ); + nOnLine = 0; + } + else + fprintf( pFile, " " ); + } + if ( nOnLine != 0 ) + fprintf( pFile, "\n" ); + if ( Gia_ManAndNum(p) ) + fprintf( pFile, "\n" ); + + Gia_ManForEachCo( p, pObj, i ) + { + fprintf( pFile, " assign n%0*d = ", nDigits, Gia_ManCoIdToId(p, i) ); + GiaHie_PrintObjLit( pFile, Gia_ObjFaninId0p(p, pObj), Gia_ObjFaninC0(pObj), nDigits ); + fprintf( pFile, ";\n" ); + } + fprintf( pFile, "\n" ); + GiaHie_DumpOutputAssignsSome( p, pFile, nDigits, Gia_ManPoNum(p) ); + fprintf( pFile, "\n" ); + + fprintf( pFile, " always @(posedge " ); + if ( fUseCtrlPis ) + GiaHie_PrintObjName( pFile, Gia_ManCiIdToId(p, 0), nDigits ); + else + fprintf( pFile, "clk" ); + fprintf( pFile, ") begin\n" ); + Gia_ManForEachRiRo( p, pObjRi, pObjRo, i ) + fprintf( pFile, " n%0*d <= n%0*d;\n", nDigits, Gia_ObjId(p, pObjRo), nDigits, Gia_ObjId(p, pObjRi) ); + fprintf( pFile, " end\n\n" ); + fprintf( pFile, "endmodule\n\n" ); + fclose( pFile ); +} /**Function************************************************************* @@ -1217,13 +1543,18 @@ static void GiaHie_DumpOutputAssigns( Gia_Man_t * p, FILE * pFile, int nDigits ) SeeAlso [] ***********************************************************************/ -static void GiaHie_DumpInterfaceAssigns( Gia_Man_t * p, char * pFileName ) +static void GiaHie_DumpInterfaceAssigns( Gia_Man_t * p, char * pFileName, int fUseCtrlPis ) { Gia_Obj_t * pObj; int nDigits = Abc_Base10Log( Gia_ManObjNum(p) ); int nPerLine = 4; int nOnLine = 0; int i; + if ( Gia_ManRegNum(p) > 0 ) + { + GiaHie_DumpInterfaceAssignsSeq( p, pFileName, fUseCtrlPis ); + return; + } FILE * pFile = fopen( pFileName, "wb" ); if ( pFile == NULL ) { @@ -1494,7 +1825,7 @@ static void GiaHie_DumpMappedLuts( Gia_Man_t * p, char * pFileName ) SeeAlso [] ***********************************************************************/ -void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose ) +void Gia_WriteVerilogInt( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose, int fUseCtrlPis ) { (void)fVerbose; if ( pFileName == NULL || pGia == NULL ) @@ -1502,7 +1833,12 @@ void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fV if ( fUseGates ) GiaHie_DumpInterfaceGates( pGia, pFileName ); else - GiaHie_DumpInterfaceAssigns( pGia, pFileName ); + GiaHie_DumpInterfaceAssigns( pGia, pFileName, fUseCtrlPis ); +} + +void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose ) +{ + Gia_WriteVerilogInt( pFileName, pGia, fUseGates, fVerbose, 0 ); } /**Function************************************************************* diff --git a/src/base/abc/abcNtk.c b/src/base/abc/abcNtk.c index 9d6c4f0ea..047cbf521 100644 --- a/src/base/abc/abcNtk.c +++ b/src/base/abc/abcNtk.c @@ -39,6 +39,86 @@ ABC_NAMESPACE_IMPL_START /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// +static int Abc_NtkDupDfsSameFanins( Abc_Obj_t * pObj0, Abc_Obj_t * pObj1 ) +{ + Abc_Obj_t * pFanin0, * pFanin1; + int i; + if ( pObj0 == NULL || pObj1 == NULL || Abc_ObjFaninNum(pObj0) != Abc_ObjFaninNum(pObj1) ) + return 0; + Abc_ObjForEachFanin( pObj0, pFanin0, i ) + { + pFanin1 = Abc_ObjFanin( pObj1, i ); + if ( pFanin0 != pFanin1 ) + return 0; + } + return 1; +} +static Abc_Obj_t * Abc_NtkDupDfsFindTwin( Vec_Ptr_t * vNodes, Vec_Int_t * vSeen, Abc_Obj_t * pObj ) +{ + Mio_Gate_t * pGate = (Mio_Gate_t *)pObj->pData; + Abc_Obj_t * pObj2; + int i; + if ( pGate == NULL || Mio_GateReadTwin(pGate) == NULL ) + return NULL; + Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj2, i ) + { + if ( pObj2 == pObj || Vec_IntEntry(vSeen, Abc_ObjId(pObj2)) ) + continue; + if ( (Mio_Gate_t *)pObj2->pData != Mio_GateReadTwin(pGate) ) + continue; + if ( Abc_NtkDupDfsSameFanins(pObj, pObj2) ) + return pObj2; + } + return NULL; +} +static Vec_Ptr_t * Abc_NtkDupDfsOrderTwinNodes( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes ) +{ + Vec_Int_t * vSeen; + Vec_Ptr_t * vRes; + Abc_Obj_t * pObj, * pTwin; + Mio_Gate_t * pGate, * pGateBase; + int i; + if ( !Abc_NtkHasMapping(pNtk) || pNtk->pManFunc == NULL ) + return vNodes; + vSeen = Vec_IntStart( Abc_NtkObjNumMax(pNtk) ); + vRes = Vec_PtrAlloc( Vec_PtrSize(vNodes) ); + Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) + { + if ( Vec_IntEntry(vSeen, Abc_ObjId(pObj)) ) + continue; + pGate = (Mio_Gate_t *)pObj->pData; + if ( pGate == NULL || Mio_GateReadTwin(pGate) == NULL ) + { + Vec_PtrPush( vRes, pObj ); + Vec_IntWriteEntry( vSeen, Abc_ObjId(pObj), 1 ); + continue; + } + pTwin = Abc_NtkDupDfsFindTwin( vNodes, vSeen, pObj ); + if ( pTwin == NULL ) + { + Vec_PtrPush( vRes, pObj ); + Vec_IntWriteEntry( vSeen, Abc_ObjId(pObj), 1 ); + continue; + } + pGateBase = Mio_LibraryReadGateByName( (Mio_Library_t *)pNtk->pManFunc, Mio_GateReadName(pGate), NULL ); + if ( pGateBase == (Mio_Gate_t *)pTwin->pData ) + { + Vec_PtrPush( vRes, pTwin ); + Vec_PtrPush( vRes, pObj ); + } + else + { + Vec_PtrPush( vRes, pObj ); + Vec_PtrPush( vRes, pTwin ); + } + Vec_IntWriteEntry( vSeen, Abc_ObjId(pObj), 1 ); + Vec_IntWriteEntry( vSeen, Abc_ObjId(pTwin), 1 ); + } + Vec_IntFree( vSeen ); + Vec_PtrFree( vNodes ); + return vRes; +} + /**Function************************************************************* Synopsis [Creates a new Ntk.] @@ -548,6 +628,7 @@ Abc_Ntk_t * Abc_NtkDupDfs( Abc_Ntk_t * pNtk ) pNtkNew = Abc_NtkStartFrom( pNtk, pNtk->ntkType, pNtk->ntkFunc ); // copy the internal nodes vNodes = Abc_NtkDfs( pNtk, 0 ); + vNodes = Abc_NtkDupDfsOrderTwinNodes( pNtk, vNodes ); Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) Abc_NtkDupObj( pNtkNew, pObj, 0 ); Vec_PtrFree( vNodes ); @@ -2621,4 +2702,3 @@ Abc_Ntk_t * Abc_NtkCreateFromGias( char * pName, Vec_Ptr_t * vGias, Gia_Man_t * ABC_NAMESPACE_IMPL_END - diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 6ddd31474..dc249282c 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -662,6 +662,9 @@ static int Abc_CommandAbc9BsFind ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9AndCare ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Cuts ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Divide ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Pipeline ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Unpipeline ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Regio ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Test ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -687,7 +690,7 @@ extern void Extra_BitMatrixTransposeP( Vec_Wrd_t * vSimsIn, int nWordsIn, Vec_Wr typedef struct Wlc_Ntk_t_ Wlc_Ntk_t; typedef struct Wlc_BstPar_t_ Wlc_BstPar_t; extern Gia_Man_t * Wlc_NtkBitBlast( Wlc_Ntk_t * p, Wlc_BstPar_t * pPars ); -extern int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile ); +extern int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile, char * pUfarArgs ); extern int Cec_GiaReplayReadParams( char * pFileName, int * pnProcs, int * pnTimeOut, int * pnTimeOut2, int * pnTimeOut3, int * pfUseUif ); extern int Cec_GiaReplayTest( Gia_Man_t * p, Wlc_Ntk_t * pWlc, char * pFileName, int fVerbose, int fVeryVerbose, int fSilent ); @@ -1515,6 +1518,9 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&andcare", Abc_CommandAbc9AndCare, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&cuts", Abc_CommandAbc9Cuts, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "÷", Abc_CommandAbc9Divide, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&pipe", Abc_CommandAbc9Pipeline, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&unpipe", Abc_CommandAbc9Unpipeline, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "®io", Abc_CommandAbc9Regio, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&test", Abc_CommandAbc9Test, 0 ); @@ -35155,18 +35161,19 @@ usage: ***********************************************************************/ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose ); + extern void Gia_WriteVerilogInt( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose, int fUseCtrlPis ); extern void Gia_WriteMappedVerilog( char * pFileName, Gia_Man_t * pGia, int fVerbose ); char * pFileSpec = NULL; Abc_Ntk_t * pNtkSpec = NULL; char * pFileName; char ** pArgvNew; int c, nArgcNew; + int fUseCtrlPis = 0; int fUseGates = 0; int fUseLuts = 0; int fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "Sglvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "Scglvh" ) ) != EOF ) { switch ( c ) { @@ -35179,6 +35186,9 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv ) pFileSpec = argv[globalUtilOptind]; globalUtilOptind++; break; + case 'c': + fUseCtrlPis ^= 1; + break; case 'g': fUseGates ^= 1; break; @@ -35222,7 +35232,7 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv ) } else { - Gia_WriteVerilog( pFileName, pAbc->pGia, fUseGates, fVerbose ); + Gia_WriteVerilogInt( pFileName, pAbc->pGia, fUseGates, fVerbose, fUseCtrlPis ); } } else @@ -35245,9 +35255,10 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &write_ver [-S ] [-glvh] \n" ); + Abc_Print( -2, "usage: &write_ver [-S ] [-cglvh] \n" ); Abc_Print( -2, "\t writes hierarchical Verilog\n" ); Abc_Print( -2, "\t-S file : file name for the original design (required when hierarchy is present)\n" ); + Abc_Print( -2, "\t-c : add clk/rst ports for seq AIGs [default = %s]\n", fUseCtrlPis? "no": "yes" ); Abc_Print( -2, "\t-g : toggle output gates vs assign-statements [default = %s]\n", fUseGates? "gates": "assigns" ); Abc_Print( -2, "\t-l : write LUT6-based Verilog for mapped AIGs [default = %s]\n", fUseLuts? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); @@ -41171,7 +41182,7 @@ int Abc_CommandAbc9Scorr( Abc_Frame_t * pAbc, int argc, char ** argv ) Cec_ManCorSetDefaultParams( pPars ); pPars->nProcs = 1; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "FCGXPSZpkrecqowvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "FCGXPSZpkrecqiowvh" ) ) != EOF ) { switch ( c ) { @@ -41270,6 +41281,9 @@ int Abc_CommandAbc9Scorr( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'q': pPars->fStopWhenGone ^= 1; break; + case 'i': + pPars->fIncremental ^= 1; + break; case 'o': fUseOld ^= 1; break; @@ -41343,7 +41357,7 @@ int Abc_CommandAbc9Scorr( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &scorr [-FCGXPSZ num] [-pkrecqowvh]\n" ); + Abc_Print( -2, "usage: &scorr [-FCGXPSZ num] [-pkrecqiowvh]\n" ); Abc_Print( -2, "\t performs signal correpondence computation\n" ); Abc_Print( -2, "\t-C num : the max number of conflicts at a node [default = %d]\n", pPars->nBTLimit ); Abc_Print( -2, "\t-F num : the number of timeframes in inductive case [default = %d]\n", pPars->nFrames ); @@ -41358,6 +41372,7 @@ usage: Abc_Print( -2, "\t-e : toggle using equivalences as choices [default = %s]\n", pPars->fMakeChoices? "yes": "no" ); Abc_Print( -2, "\t-c : toggle using circuit-based SAT solver [default = %s]\n", pPars->fUseCSat? "yes": "no" ); Abc_Print( -2, "\t-q : toggle quitting when PO is not a constant candidate [default = %s]\n", pPars->fStopWhenGone? "yes": "no" ); + Abc_Print( -2, "\t-i : toggle incremental TFO-triggered re-proof in main loop [default = %s] by Xiran ZHao at University of Chinese Academy of Sciences\n", pPars->fIncremental? "yes": "no" ); Abc_Print( -2, "\t-o : toggle calling old engine [default = %s]\n", fUseOld? "yes": "no" ); Abc_Print( -2, "\t-w : toggle printing verbose info about equivalent flops [default = %s]\n", pPars->fVerboseFlops? "yes": "no" ); Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", pPars->fVerbose? "yes": "no" ); @@ -51574,10 +51589,10 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) { Gia_Man_t * pGiaUse = pAbc->pGia, * pGiaTemp = NULL; Wlc_Ntk_t * pWlc = (Wlc_Ntk_t *)pAbc->pAbcWlc; - char * pReplayFile = NULL; + char * pReplayFile = NULL, * pUfarArgs = NULL, * pUfarArgsAlloc = NULL; int c, nProcs = 6, nProcsNew = 0, nTimeOut = 3, nTimeOut2 = 10, nTimeOut3 = 100, fUseUif = 0, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "PTUWRusvwh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "PTUCWRusvwh" ) ) != EOF ) { switch ( c ) { @@ -51614,7 +51629,30 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) globalUtilOptind++; if ( nTimeOut2 <= 0 ) goto usage; - break; + break; + case 'C': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-C\" should be followed by a string.\n" ); + goto usage; + } + { + int iArg, nChars = 0; + ABC_FREE( pUfarArgsAlloc ); + for ( iArg = globalUtilOptind; iArg < argc; iArg++ ) + nChars += (int)strlen(argv[iArg]) + 1; + pUfarArgsAlloc = ABC_ALLOC( char, nChars + 1 ); + pUfarArgsAlloc[0] = 0; + for ( iArg = globalUtilOptind; iArg < argc; iArg++ ) + { + if ( iArg > globalUtilOptind ) + strcat( pUfarArgsAlloc, " " ); + strcat( pUfarArgsAlloc, argv[iArg] ); + } + pUfarArgs = pUfarArgsAlloc; + globalUtilOptind = argc; + } + break; case 'W': if ( globalUtilOptind >= argc ) { @@ -51659,27 +51697,37 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( pWlc == NULL ) { Abc_Print( -1, "Abc_CommandAbc9SProve(): There is no word-level design for option \"-u\".\n" ); + ABC_FREE( pUfarArgsAlloc ); return 1; } pGiaTemp = Wlc_NtkBitBlast( pWlc, NULL ); if ( pGiaTemp == NULL ) { Abc_Print( -1, "Abc_CommandAbc9SProve(): Word-level bit-blasting has failed.\n" ); + ABC_FREE( pUfarArgsAlloc ); return 1; } if ( (Gia_ManPoNum(pGiaTemp) & 1) == 1 ) { Abc_Print( -1, "Abc_CommandAbc9SProve(): Internal \"&miter -x\" requires even number of bit-level outputs.\n" ); Gia_ManStop( pGiaTemp ); + ABC_FREE( pUfarArgsAlloc ); return 1; } pGiaUse = Gia_ManTransformMiter2( pGiaTemp ); Gia_ManStop( pGiaTemp ); pGiaTemp = NULL; } + else if ( pUfarArgs != NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9SProve(): Option \"-C\" requires \"-u\".\n" ); + ABC_FREE( pUfarArgsAlloc ); + return 1; + } if ( pGiaUse == NULL ) { Abc_Print( -1, "Abc_CommandAbc9SProve(): There is no AIG.\n" ); + ABC_FREE( pUfarArgsAlloc ); return 1; } if ( Gia_ManRegNum(pGiaUse) == 0 ) @@ -51687,20 +51735,23 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Abc_CommandAbc9SProve(): The problem is combinational.\n" ); if ( fUseUif ) Gia_ManStop( pGiaUse ); + ABC_FREE( pUfarArgsAlloc ); return 1; } - pAbc->Status = Cec_GiaProveTest( pGiaUse, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fUseUif, pWlc, fVerbose, fVeryVerbose, fSilent, pReplayFile ); + pAbc->Status = Cec_GiaProveTest( pGiaUse, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fUseUif, pWlc, fVerbose, fVeryVerbose, fSilent, pReplayFile, pUfarArgs ); Abc_FrameReplaceCex( pAbc, &pGiaUse->pCexSeq ); if ( fUseUif ) Gia_ManStop( pGiaUse ); + ABC_FREE( pUfarArgsAlloc ); return 0; usage: - Abc_Print( -2, "usage: &sprove [-PTUW num] [-R file] [-usvwh]\n" ); + Abc_Print( -2, "usage: &sprove [-PTUW num] [-C str] [-R file] [-usvwh]\n" ); Abc_Print( -2, "\t proves CEC problem by case-splitting\n" ); Abc_Print( -2, "\t-P num : the number of concurrent processes (1 <= num <= 6) [default = %d]\n", nProcs ); Abc_Print( -2, "\t-T num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut ); - Abc_Print( -2, "\t-U num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut2 ); + Abc_Print( -2, "\t-U num : second-stage timeout in seconds [default = %d]\n", nTimeOut2 ); + Abc_Print( -2, "\t-C str : with -u, pass this option string to internal %%ufar\n" ); Abc_Print( -2, "\t-W num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut3 ); Abc_Print( -2, "\t-R str : dump replay/trace file for later execution by &sprove2\n" ); Abc_Print( -2, "\t-u : enable concurrent UFAR on word-level design (uses internal %%blast + &miter -x)\n" ); @@ -51708,6 +51759,7 @@ usage: Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-w : toggle printing more verbose information [default = %s]\n", fVeryVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); + ABC_FREE( pUfarArgsAlloc ); return 1; } @@ -59869,6 +59921,213 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Pipeline( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Gia_Man_t * Gia_ManDupPipeline( Gia_Man_t * p, int nLevels, int fVerbose ); + Gia_Man_t * pGiaNew; + int nLevels = 20; + int nDelayMax, c, fVerbose = 0; + + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "Dvh" ) ) != EOF ) + { + switch ( c ) + { + case 'D': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-D\" should be followed by a positive integer.\n" ); + goto usage; + } + nLevels = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nLevels <= 0 ) + goto usage; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Pipeline(): There is no AIG.\n" ); + return 1; + } + if ( Gia_ManRegNum(pAbc->pGia) > 0 ) + { + Abc_Print( -1, "Abc_CommandAbc9Pipeline(): This command expects a combinational AIG.\n" ); + return 1; + } + + pGiaNew = Gia_ManDupPipeline( pAbc->pGia, nLevels, fVerbose ); + if ( pGiaNew == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Pipeline(): Pipelining has failed.\n" ); + return 1; + } + nDelayMax = Gia_ManLevelNum( pGiaNew ); + if ( nDelayMax > nLevels ) + { + Abc_Print( -1, "Abc_CommandAbc9Pipeline(): Seed pipeline delay (%d) exceeds target D = %d.\n", nDelayMax, nLevels ); + Gia_ManStop( pGiaNew ); + return 1; + } + Abc_FrameUpdateGia( pAbc, pGiaNew ); + return 0; + +usage: + Abc_Print( -2, "usage: &pipe [-D num] [-vh]\n" ); + Abc_Print( -2, "\t inserts pipeline stages\n" ); + Abc_Print( -2, "\t-D num : max AIG levels between the flops [default = %d]\n", nLevels ); + Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose ? "yes" : "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Unpipeline( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Gia_Man_t * Gia_ManDupUnpipeline( Gia_Man_t * p, int fVerbose ); + Gia_Man_t * pGiaNew; + int c, fVerbose = 0; + + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF ) + { + switch ( c ) + { + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Unpipeline(): There is no AIG.\n" ); + return 1; + } + if ( Gia_ManRegNum(pAbc->pGia) == 0 ) + { + if ( fVerbose ) + Abc_Print( 1, "Abc_CommandAbc9Unpipeline(): The current AIG is already combinational.\n" ); + return 0; + } + + pGiaNew = Gia_ManDupUnpipeline( pAbc->pGia, fVerbose ); + if ( pGiaNew == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Unpipeline(): Removing pipeline flops has failed.\n" ); + return 1; + } + Abc_FrameUpdateGia( pAbc, pGiaNew ); + return 0; + +usage: + Abc_Print( -2, "usage: &unpipe [-vh]\n" ); + Abc_Print( -2, "\t removes the flops to derive a combinational AIG\n" ); + Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose ? "yes" : "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Regio( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Gia_Man_t * Gia_ManDupRegio( Gia_Man_t * p, int fRegIns, int fRegOuts, int fVerbose ); + Gia_Man_t * pGiaNew; + int c, fRegIns = 1, fRegOuts = 1, fVerbose = 0; + + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "iovh" ) ) != EOF ) + { + switch ( c ) + { + case 'i': + fRegIns ^= 1; + break; + case 'o': + fRegOuts ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Regio(): There is no AIG.\n" ); + return 1; + } + if ( !fRegIns && !fRegOuts ) + { + if ( fVerbose ) + Abc_Print( 1, "Abc_CommandAbc9Regio(): No boundary flops are requested.\n" ); + return 0; + } + + pGiaNew = Gia_ManDupRegio( pAbc->pGia, fRegIns, fRegOuts, fVerbose ); + if ( pGiaNew == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Regio(): Adding boundary flops has failed.\n" ); + return 1; + } + Abc_FrameUpdateGia( pAbc, pGiaNew ); + return 0; + +usage: + Abc_Print( -2, "usage: ®io [-iovh]\n" ); + Abc_Print( -2, "\t adds PI/PO flops while preserving the current AIG\n" ); + Abc_Print( -2, "\t-i : toggle adding PI flops [default = %s]\n", fRegIns ? "yes" : "no" ); + Abc_Print( -2, "\t-o : toggle adding PO flops [default = %s]\n", fRegOuts ? "yes" : "no" ); + Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose ? "yes" : "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/base/io/ioJsonc.c b/src/base/io/ioJsonc.c index 5efffe995..ce069a18a 100644 --- a/src/base/io/ioJsonc.c +++ b/src/base/io/ioJsonc.c @@ -108,6 +108,8 @@ void json_print_string(json_t *json, json_value_t val, FILE *fp); void json_debug_value(json_t *json, json_value_t val, int indent); extern Abc_Ntk_t * Abc_NtkFromMiniMapping( int * pArray ); +static json_value_t * Jsonc_ObjectLookup( json_t * pJson, json_value_t object, const char * pKey ); +static char * Jsonc_StringDup( json_t * pJson, json_value_t value ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// @@ -671,6 +673,68 @@ static const char * Jsonc_GetNodeOutName( Abc_Obj_t * pObj ) snprintf( Buffer, sizeof(Buffer), "n%d", Abc_ObjId(pObj) ); return Buffer; } +static char * Jsonc_GetInstanceOutName( json_t * pJson, json_value_t Node ) +{ + json_value_t * pOutName = Jsonc_ObjectLookup( pJson, Node, "pin" ); + if ( pOutName == NULL ) + pOutName = Jsonc_ObjectLookup( pJson, Node, "output" ); + return pOutName && pOutName->type == JSON_STRING ? Jsonc_StringDup( pJson, *pOutName ) : NULL; +} +static int Jsonc_IsPrevTwinNode( Abc_Obj_t * pObj, Abc_Obj_t ** ppPrev ) +{ + Abc_Obj_t * pPrev; + Mio_Gate_t * pGate = (Mio_Gate_t *)pObj->pData; + if ( ppPrev ) + *ppPrev = NULL; + if ( pGate == NULL || Mio_GateReadTwin(pGate) == NULL || Abc_ObjId(pObj) == 0 ) + return 0; + pPrev = Abc_NtkObj( pObj->pNtk, Abc_ObjId(pObj) - 1 ); + if ( pPrev == NULL || !Abc_ObjIsNode(pPrev) || Abc_ObjFaninNum(pPrev) != Abc_ObjFaninNum(pObj) ) + return 0; + if ( Mio_GateReadTwin(pGate) != (Mio_Gate_t *)pPrev->pData ) + return 0; + if ( ppPrev ) + *ppPrev = pPrev; + return 1; +} +static Vec_Ptr_t * Jsonc_OrderTwinNodes( Abc_Ntk_t * p, Vec_Ptr_t * vNodes ) +{ + Vec_Int_t * vInDfs = Vec_IntStart( Abc_NtkObjNumMax(p) ); + Vec_Int_t * vSeen = Vec_IntStart( Abc_NtkObjNumMax(p) ); + Vec_Ptr_t * vRes = Vec_PtrAlloc( Vec_PtrSize(vNodes) ); + Abc_Obj_t * pObj, * pTwin; + int i; + Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) + Vec_IntWriteEntry( vInDfs, Abc_ObjId(pObj), 1 ); + Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) + { + if ( Vec_IntEntry(vSeen, Abc_ObjId(pObj)) ) + continue; + if ( Jsonc_IsPrevTwinNode( pObj, &pTwin ) && Vec_IntEntry(vInDfs, Abc_ObjId(pTwin)) ) + { + if ( !Vec_IntEntry(vSeen, Abc_ObjId(pTwin)) ) + { + Vec_PtrPush( vRes, pTwin ); + Vec_IntWriteEntry( vSeen, Abc_ObjId(pTwin), 1 ); + } + Vec_PtrPush( vRes, pObj ); + Vec_IntWriteEntry( vSeen, Abc_ObjId(pObj), 1 ); + continue; + } + Vec_PtrPush( vRes, pObj ); + Vec_IntWriteEntry( vSeen, Abc_ObjId(pObj), 1 ); + pTwin = Abc_NtkFetchTwinNode( pObj ); + if ( pTwin && Vec_IntEntry(vInDfs, Abc_ObjId(pTwin)) && !Vec_IntEntry(vSeen, Abc_ObjId(pTwin)) ) + { + Vec_PtrPush( vRes, pTwin ); + Vec_IntWriteEntry( vSeen, Abc_ObjId(pTwin), 1 ); + } + } + assert( Vec_PtrSize(vRes) == Vec_PtrSize(vNodes) ); + Vec_IntFree( vInDfs ); + Vec_IntFree( vSeen ); + return vRes; +} /**Function************************************************************* @@ -692,8 +756,18 @@ void Jsonc_WriteTest( Abc_Ntk_t * p, char * pFileName ) int i, Counter, Total; assert( Abc_NtkHasMapping(p) ); vNodes = Abc_NtkDfs2( p ); + { + Vec_Ptr_t * vTemp = Jsonc_OrderTwinNodes( p, vNodes ); + Vec_PtrFree( vNodes ); + vNodes = vTemp; + } vObj2Num = Vec_IntStartFull( Abc_NtkObjNumMax(p) ); Total = Abc_NtkPiNum(p) + Vec_PtrSize(vNodes) + Abc_NtkPoNum(p); + Counter = 0; + Abc_NtkForEachPi( p, pObj, i ) + Vec_IntWriteEntry( vObj2Num, Abc_ObjId(pObj), Counter++ ); + Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) + Vec_IntWriteEntry( vObj2Num, Abc_ObjId(pObj), Counter++ ); pFile = fopen( pFileName, "wb" ); if ( pFile == NULL ) { @@ -727,6 +801,8 @@ void Jsonc_WriteTest( Abc_Ntk_t * p, char * pFileName ) fprintf( pFile, " {\n" ); fprintf( pFile, " \"type\": \"%s\",\n", "instance" ); fprintf( pFile, " \"name\": \"%s\",\n", Mio_GateReadName(pGate) ); + if ( Mio_GateReadTwin(pGate) != NULL ) + fprintf( pFile, " \"pin\": \"%s\",\n", Mio_GateReadOutName(pGate) ); fprintf( pFile, " \"fanins\":\n" ); fprintf( pFile, " {\n" ); for ( pPin = Mio_GateReadPins(pGate), k = 0; pPin; pPin = Mio_PinReadNext(pPin), k++ ) @@ -897,9 +973,10 @@ static void Jsonc_AppendPortNames( Vec_Str_t * vNames, Vec_Ptr_t * vBases, Vec_I Vec_IntFree( vCounts ); Vec_IntFree( vBaseIds ); } -static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * pLib, char ** ppDesignName ) +static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * pLib, char ** ppDesignName, Vec_Ptr_t ** pvNodeOutNames ) { Vec_Ptr_t * vPiBases = NULL, * vPoBases = NULL; + Vec_Ptr_t * vNodeOutNames = NULL; Vec_Int_t * vPiBits = NULL, * vPoBits = NULL; Vec_Int_t * vNodeMap = NULL, * vGateIdx = NULL, * vPoIdx = NULL; Vec_Int_t * vMapping = NULL, * vPoDrivers = NULL; @@ -911,6 +988,8 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p int fSuccess = 0; if ( ppDesignName ) *ppDesignName = NULL; + if ( pvNodeOutNames ) + *pvNodeOutNames = NULL; if ( pLib == NULL ) { printf( "Genlib library is not available.\n" ); @@ -943,6 +1022,7 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p vPiBits = Vec_IntAlloc( pNodes->count ); vPoBases = Vec_PtrAlloc( pNodes->count ); vPoBits = Vec_IntAlloc( pNodes->count ); + vNodeOutNames = Vec_PtrAlloc( pNodes->count ); // first pass: collect object types and names for ( i = 0; i < (int)pNodes->count; i++ ) { @@ -1020,7 +1100,7 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p json_container_t * pFanObj; Mio_Gate_t * pGate; Mio_Pin_t * pPin; - char * pGateStr; + char * pGateStr, * pOutStr; if ( pGateName == NULL || pGateName->type != JSON_STRING ) { printf( "Gate node %d is missing a name.\n", i ); @@ -1032,16 +1112,19 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p printf( "Gate node %d has an invalid name.\n", i ); goto cleanup; } - pGate = Mio_LibraryReadGateByName( pLib, pGateStr, NULL ); + pOutStr = Jsonc_GetInstanceOutName( pJson, Node ); + pGate = Mio_LibraryReadGateByName( pLib, pGateStr, pOutStr ); if ( pGate == NULL ) { - printf( "Gate \"%s\" is not found in the current library.\n", pGateStr ); + printf( "Gate \"%s\"%s%s%s is not found in the current library.\n", pGateStr, pOutStr ? " with output pin \"" : "", pOutStr ? pOutStr : "", pOutStr ? "\"" : "" ); + ABC_FREE( pOutStr ); ABC_FREE( pGateStr ); goto cleanup; } if ( pFanins == NULL || pFanins->type != JSON_OBJECT ) { printf( "Gate \"%s\" is missing \"fanins\" description.\n", pGateStr ); + ABC_FREE( pOutStr ); ABC_FREE( pGateStr ); goto cleanup; } @@ -1049,6 +1132,7 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p if ( pFanObj == NULL ) { printf( "Gate \"%s\" has incomplete fanin information.\n", pGateStr ); + ABC_FREE( pOutStr ); ABC_FREE( pGateStr ); goto cleanup; } @@ -1061,6 +1145,7 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p if ( pPinInfo == NULL || pPinInfo->type != JSON_OBJECT ) { printf( "Gate \"%s\" is missing connection for pin \"%s\".\n", pGateStr, Mio_PinReadName(pPin) ); + ABC_FREE( pOutStr ); ABC_FREE( pGateStr ); goto cleanup; } @@ -1068,12 +1153,14 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p if ( pNodeLit == NULL || !Jsonc_ParseInt( pJson, *pNodeLit, &NodeId ) ) { printf( "Gate \"%s\" has invalid node reference on pin \"%s\".\n", pGateStr, Mio_PinReadName(pPin) ); + ABC_FREE( pOutStr ); ABC_FREE( pGateStr ); goto cleanup; } if ( NodeId < 0 || NodeId >= Vec_IntSize(vNodeMap) ) { printf( "Gate \"%s\" references out-of-range node %d.\n", pGateStr, NodeId ); + ABC_FREE( pOutStr ); ABC_FREE( pGateStr ); goto cleanup; } @@ -1081,6 +1168,7 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p if ( MapId < 0 ) { printf( "Gate \"%s\" refers to unsupported node %d.\n", pGateStr, NodeId ); + ABC_FREE( pOutStr ); ABC_FREE( pGateStr ); goto cleanup; } @@ -1088,6 +1176,7 @@ static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * p } Vec_StrPrintStr( vNames, pGateStr ); Vec_StrPush( vNames, '\0' ); + Vec_PtrPush( vNodeOutNames, pOutStr ); ABC_FREE( pGateStr ); } else if ( Jsonc_StringEqual( pJson, *pType, "PO" ) || Jsonc_StringEqual( pJson, *pType, "po" ) ) @@ -1148,6 +1237,18 @@ cleanup: Vec_IntFreeP( &vPoBits ); if ( vNames ) Vec_StrFree( vNames ); + if ( vNodeOutNames ) + { + if ( fSuccess && pvNodeOutNames ) + *pvNodeOutNames = vNodeOutNames; + else + { + char * pOutName; + Vec_PtrForEachEntry( char *, vNodeOutNames, pOutName, i ) + ABC_FREE( pOutName ); + Vec_PtrFree( vNodeOutNames ); + } + } if ( vPiBases ) { Vec_PtrForEachEntry( char *, vPiBases, pBase, i ) @@ -1171,8 +1272,12 @@ Abc_Ntk_t * Jsonc_ReadNetwork( char * pFileName ) { Mio_Library_t * pLib = (Mio_Library_t *)Abc_FrameReadLibGen(); Vec_Int_t * vMapping; + Vec_Ptr_t * vNodeOutNames = NULL; Abc_Ntk_t * pNtk; + Abc_Obj_t * pObj; char * pDesignName = NULL; + char * pOutName; + int i; json_t * pJson = json_create(); if ( pJson == NULL ) { @@ -1185,7 +1290,7 @@ Abc_Ntk_t * Jsonc_ReadNetwork( char * pFileName ) json_destroy( pJson ); return NULL; } - vMapping = Jsonc_ConvertToMiniMapping( pJson, pLib, &pDesignName ); + vMapping = Jsonc_ConvertToMiniMapping( pJson, pLib, &pDesignName, &vNodeOutNames ); json_destroy( pJson ); if ( vMapping == NULL ) return NULL; @@ -1193,9 +1298,35 @@ Abc_Ntk_t * Jsonc_ReadNetwork( char * pFileName ) Vec_IntFree( vMapping ); if ( pNtk == NULL ) { + if ( vNodeOutNames ) + { + Vec_PtrForEachEntry( char *, vNodeOutNames, pOutName, i ) + ABC_FREE( pOutName ); + Vec_PtrFree( vNodeOutNames ); + } ABC_FREE( pDesignName ); return NULL; } + if ( vNodeOutNames ) + { + Vec_PtrForEachEntry( char *, vNodeOutNames, pOutName, i ) + { + Mio_Gate_t * pGate; + pObj = Abc_NtkObj( pNtk, Abc_NtkCiNum(pNtk) + i + 1 ); + if ( pObj == NULL ) + continue; + pGate = (Mio_Gate_t *)pObj->pData; + if ( pOutName && pGate ) + { + Mio_Gate_t * pGateOut = Mio_LibraryReadGateByName( pLib, Mio_GateReadName(pGate), pOutName ); + if ( pGateOut ) + pObj->pData = pGateOut; + } + } + Vec_PtrForEachEntry( char *, vNodeOutNames, pOutName, i ) + ABC_FREE( pOutName ); + Vec_PtrFree( vNodeOutNames ); + } ABC_FREE( pNtk->pName ); pNtk->pName = pDesignName ? pDesignName : Extra_FileNameGeneric( pFileName ); ABC_FREE( pNtk->pSpec ); diff --git a/src/base/io/ioReadBlif.c b/src/base/io/ioReadBlif.c index e8979c9ba..38e863813 100644 --- a/src/base/io/ioReadBlif.c +++ b/src/base/io/ioReadBlif.c @@ -622,46 +622,65 @@ int Io_ReadBlifReorderFormalNames( Vec_Ptr_t * vTokens, Mio_Gate_t * pGate, Mio_ } else { - if ( i != Mio_GateReadPinNum(pGate) ) // expect the correct order of input pins in the network with twin gates + int nInputs = Mio_GateReadPinNum(pGate); + int nOutputs = nSize - 2 - nInputs; + int nMatched = 0; + if ( nOutputs != 1 && nOutputs != 2 ) return 0; - // check the last two entries - if ( nSize - 3 == Mio_GateReadPinNum(pGate) ) // only one output is available + // reorder the input pins to be in the same order as in the gate + for ( pGatePin = Mio_GateReadPins(pGate), i = 0; pGatePin; pGatePin = Mio_PinReadNext(pGatePin), i++ ) { - pNamePin = Mio_GateReadOutName(pGate); + pNamePin = Mio_PinReadName(pGatePin); Length = strlen(pNamePin); - pName = (char *)Vec_PtrEntry(vTokens, nSize - 1); - if ( !strncmp( pNamePin, pName, Length ) && pName[Length] == '=' ) // the last entry is pGate + for ( k = 2; k < nSize; k++ ) { - Vec_PtrPush( vTokens, NULL ); - return 1; + pName = (char *)Vec_PtrEntry(vTokens, k); + if ( !strncmp( pNamePin, pName, Length ) && pName[Length] == '=' ) + { + Vec_PtrPush( vTokens, pName ); + nMatched++; + break; + } } - pNamePin = Mio_GateReadOutName(pTwin); - Length = strlen(pNamePin); - pName = (char *)Vec_PtrEntry(vTokens, nSize - 1); - if ( !strncmp( pNamePin, pName, Length ) && pName[Length] == '=' ) // the last entry is pTwin + if ( k == nSize ) + return 0; + } + // add the outputs in the base/twin order, with NULL for a missing output + pNamePin = Mio_GateReadOutName(pGate); + Length = strlen(pNamePin); + for ( k = 2; k < nSize; k++ ) + { + pName = (char *)Vec_PtrEntry(vTokens, k); + if ( !strncmp( pNamePin, pName, Length ) && pName[Length] == '=' ) { - pName = (char *)Vec_PtrPop( vTokens ); - Vec_PtrPush( vTokens, NULL ); Vec_PtrPush( vTokens, pName ); - return 1; + nMatched++; + break; } - return 0; } - if ( nSize - 4 == Mio_GateReadPinNum(pGate) ) // two outputs are available + if ( k == nSize ) + Vec_PtrPush( vTokens, NULL ); + pNamePin = Mio_GateReadOutName(pTwin); + Length = strlen(pNamePin); + for ( k = 2; k < nSize; k++ ) { - pNamePin = Mio_GateReadOutName(pGate); - Length = strlen(pNamePin); - pName = (char *)Vec_PtrEntry(vTokens, nSize - 2); - if ( !(!strncmp( pNamePin, pName, Length ) && pName[Length] == '=') ) - return 0; - pNamePin = Mio_GateReadOutName(pTwin); - Length = strlen(pNamePin); - pName = (char *)Vec_PtrEntry(vTokens, nSize - 1); - if ( !(!strncmp( pNamePin, pName, Length ) && pName[Length] == '=') ) - return 0; - return 1; + pName = (char *)Vec_PtrEntry(vTokens, k); + if ( !strncmp( pNamePin, pName, Length ) && pName[Length] == '=' ) + { + Vec_PtrPush( vTokens, pName ); + nMatched++; + break; + } } - assert( 0 ); + if ( k == nSize ) + Vec_PtrPush( vTokens, NULL ); + if ( Vec_PtrEntry(vTokens, nSize + nInputs) == NULL && Vec_PtrEntry(vTokens, nSize + nInputs + 1) == NULL ) + return 0; + if ( nMatched != nSize - 2 ) + return 0; + Vec_PtrForEachEntryStart( char *, vTokens, pName, k, nSize ) + Vec_PtrWriteEntry( vTokens, k - nSize + 2, pName ); + Vec_PtrShrink( vTokens, 2 + nInputs + 2 ); } return 1; } @@ -1713,4 +1732,3 @@ int Io_ReadBlifNetworkConnectBoxes( Io_ReadBlif_t * p, Abc_Ntk_t * pNtkMaster ) ABC_NAMESPACE_IMPL_END - diff --git a/src/base/io/ioWriteBlif.c b/src/base/io/ioWriteBlif.c index 818f66b37..71a40f96c 100644 --- a/src/base/io/ioWriteBlif.c +++ b/src/base/io/ioWriteBlif.c @@ -573,6 +573,17 @@ void Io_NtkWriteSubcktFanins( FILE * pFile, Abc_Obj_t * pNode ) SeeAlso [] ***********************************************************************/ +static int Io_NtkNodesHaveSameFanins( Abc_Obj_t * pNode, Abc_Obj_t * pNode2 ) +{ + Abc_Obj_t * pFanin; + int i; + if ( Abc_ObjFaninNum(pNode) != Abc_ObjFaninNum(pNode2) ) + return 0; + Abc_ObjForEachFanin( pNode, pFanin, i ) + if ( pFanin != Abc_ObjFanin(pNode2, i) ) + return 0; + return 1; +} int Io_NtkWriteNodeGate( FILE * pFile, Abc_Obj_t * pNode, int Length ) { static int fReport = 0; @@ -594,6 +605,8 @@ int Io_NtkWriteNodeGate( FILE * pFile, Abc_Obj_t * pNode, int Length ) fReport = 1, printf( "Warning: Missing second output of gate(s) \"%s\".\n", Mio_GateReadName(pGate) ); return 0; } + if ( !Io_NtkNodesHaveSameFanins( pNode, pNode2 ) ) + return 0; fprintf( pFile, " %s=%s", Mio_GateReadOutName((Mio_Gate_t *)pNode2->pData), Abc_ObjName( Abc_ObjFanout0(pNode2) ) ); return 1; } @@ -1407,4 +1420,3 @@ void Io_WriteBlifSpecial( Abc_Ntk_t * pNtk, char * FileName, char * pLutStruct, ABC_NAMESPACE_IMPL_END - diff --git a/src/base/io/ioWritePla.c b/src/base/io/ioWritePla.c index aa6a933d8..45dc74530 100644 --- a/src/base/io/ioWritePla.c +++ b/src/base/io/ioWritePla.c @@ -174,7 +174,7 @@ int Io_WritePla( Abc_Ntk_t * pNtk, char * pFileName ) FILE * pFile; assert( Abc_NtkIsSopNetlist(pNtk) ); - assert( Abc_NtkLevel(pNtk) == 1 ); + assert( Abc_NtkLevel(pNtk) <= 1 ); pFile = fopen( pFileName, "w" ); if ( pFile == NULL ) diff --git a/src/base/io/ioWriteVerilog.c b/src/base/io/ioWriteVerilog.c index acddb7551..4d3b06fcd 100644 --- a/src/base/io/ioWriteVerilog.c +++ b/src/base/io/ioWriteVerilog.c @@ -39,6 +39,8 @@ static void Io_WriteVerilogLatches( FILE * pFile, Abc_Ntk_t * pNtk ); static void Io_WriteVerilogObjects( FILE * pFile, Abc_Ntk_t * pNtk, int fOnlyAnds ); static int Io_WriteVerilogWiresCount( Abc_Ntk_t * pNtk ); static char * Io_WriteVerilogGetName( char * pName ); +static int Io_WriteVerilogNodesHaveSameFanins( Abc_Obj_t * pNode, Abc_Obj_t * pNode2 ); +static int Io_WriteVerilogIsPrevTwinNode( Abc_Obj_t * pNode ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// @@ -512,6 +514,54 @@ void Io_WriteVerilogLatches( FILE * pFile, Abc_Ntk_t * pNtk ) fprintf( pFile, " end\n" ); } +/**Function************************************************************* + + Synopsis [Checks whether two mapped nodes have the same fanins.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Io_WriteVerilogNodesHaveSameFanins( Abc_Obj_t * pNode, Abc_Obj_t * pNode2 ) +{ + Abc_Obj_t * pFanin; + int i; + if ( Abc_ObjFaninNum(pNode) != Abc_ObjFaninNum(pNode2) ) + return 0; + Abc_ObjForEachFanin( pNode, pFanin, i ) + if ( pFanin != Abc_ObjFanin(pNode2, i) ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Checks whether this mapped node is the second output of a twin.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Io_WriteVerilogIsPrevTwinNode( Abc_Obj_t * pNode ) +{ + Abc_Obj_t * pPrev; + Mio_Gate_t * pGate = (Mio_Gate_t *)pNode->pData; + if ( pGate == NULL || Mio_GateReadTwin(pGate) == NULL || Abc_ObjId(pNode) == 0 ) + return 0; + pPrev = Abc_NtkObj( pNode->pNtk, Abc_ObjId(pNode) - 1 ); + if ( pPrev == NULL || !Abc_ObjIsNode(pPrev) ) + return 0; + if ( Mio_GateReadTwin(pGate) != (Mio_Gate_t *)pPrev->pData ) + return 0; + return Io_WriteVerilogNodesHaveSameFanins( pPrev, pNode ); +} + /**Function************************************************************* Synopsis [Writes the nodes and boxes.] @@ -563,12 +613,18 @@ void Io_WriteVerilogObjects( FILE * pFile, Abc_Ntk_t * pNtk, int fOnlyAnds ) Abc_NtkForEachNode( pNtk, pObj, k ) { Mio_Gate_t * pGate = (Mio_Gate_t *)pObj->pData; + Abc_Obj_t * pNode2 = NULL; Mio_Pin_t * pGatePin; + if ( Io_WriteVerilogIsPrevTwinNode( pObj ) ) + continue; if ( Abc_ObjFaninNum(pObj) == 0 && (!strcmp(Mio_GateReadName(pGate), "_const0_") || !strcmp(Mio_GateReadName(pGate), "_const1_")) ) { fprintf( pFile, " %-*s %s = 1\'b%d;\n", Length, "assign", Io_WriteVerilogGetName(Abc_ObjName( Abc_ObjFanout0(pObj) )), !strcmp(Mio_GateReadName(pGate), "_const1_") ); continue; } + pNode2 = Abc_NtkFetchTwinNode( pObj ); + if ( pNode2 && !Io_WriteVerilogNodesHaveSameFanins( pObj, pNode2 ) ) + pNode2 = NULL; // write the node if ( fUseSimpleGateNames ) { @@ -591,6 +647,12 @@ void Io_WriteVerilogObjects( FILE * pFile, Abc_Ntk_t * pNtk, int fOnlyAnds ) assert ( i == Abc_ObjFaninNum(pObj) ); fprintf( pFile, ".%s", Io_WriteVerilogGetName(Mio_GateReadOutName(pGate)) ); fprintf( pFile, "(%s)", Io_WriteVerilogGetName(Abc_ObjName( Abc_ObjFanout0(pObj) )) ); + if ( pNode2 ) + { + fprintf( pFile, ", " ); + fprintf( pFile, ".%s", Io_WriteVerilogGetName(Mio_GateReadOutName((Mio_Gate_t *)pNode2->pData)) ); + fprintf( pFile, "(%s)", Io_WriteVerilogGetName(Abc_ObjName( Abc_ObjFanout0(pNode2) )) ); + } fprintf( pFile, ");\n" ); } } @@ -972,4 +1034,3 @@ void Io_WriteVerilogLut( Abc_Ntk_t * pNtk, char * pFileName, int nLutSize, int f ABC_NAMESPACE_IMPL_END - diff --git a/src/base/main/mainInit.c b/src/base/main/mainInit.c index 03c6f94c0..652766248 100644 --- a/src/base/main/mainInit.c +++ b/src/base/main/mainInit.c @@ -47,6 +47,8 @@ extern void Load_Init( Abc_Frame_t * pAbc ); extern void Load_End( Abc_Frame_t * pAbc ); extern void Scl_Init( Abc_Frame_t * pAbc ); extern void Scl_End( Abc_Frame_t * pAbc ); +extern void Emap_Init( Abc_Frame_t * pAbc ); +extern void Emap_End( Abc_Frame_t * pAbc ); extern void Wlc_Init( Abc_Frame_t * pAbc ); extern void Wlc_End( Abc_Frame_t * pAbc ); extern void Wln_Init( Abc_Frame_t * pAbc ); @@ -118,6 +120,7 @@ void Abc_FrameInit( Abc_Frame_t * pAbc ) Libs_Init( pAbc ); Load_Init( pAbc ); Scl_Init( pAbc ); + Emap_Init( pAbc ); Wlc_Init( pAbc ); Wln_Init( pAbc ); Bac_Init( pAbc ); @@ -159,6 +162,7 @@ void Abc_FrameEnd( Abc_Frame_t * pAbc ) Super_End( pAbc ); Libs_End( pAbc ); Load_End( pAbc ); + Emap_End( pAbc ); Scl_End( pAbc ); Wlc_End( pAbc ); Wln_End( pAbc ); diff --git a/src/map/emap/emap.c b/src/map/emap/emap.c new file mode 100644 index 000000000..3b24b1e37 --- /dev/null +++ b/src/map/emap/emap.c @@ -0,0 +1,158 @@ +/**CFile**************************************************************** + + FileName [emap.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Multi-output gate mapper.] + + Synopsis [ABC command entry points.] + +***********************************************************************/ + +#include "emap.h" + +#include "base/abc/abc.h" +#include "base/cmd/cmd.h" +#include "base/main/mainInt.h" +#include "map/mio/mio.h" +#include "misc/extra/extra.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static int Emap_CommandCountMogPairs( Mio_Library_t * pLib ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Starts the package.] + +***********************************************************************/ +void Emap_Init( Abc_Frame_t * pAbc ) +{ + Cmd_CommandAdd( pAbc, "SC mapping", "emap", Emap_Command, 1 ); +} + +/**Function************************************************************* + + Synopsis [Stops the package.] + +***********************************************************************/ +void Emap_End( Abc_Frame_t * pAbc ) +{ + (void)pAbc; +} + +/**Function************************************************************* + + Synopsis [Counts physical two-output gates represented as twin gates.] + +***********************************************************************/ +static int Emap_CommandCountMogPairs( Mio_Library_t * pLib ) +{ + Mio_Gate_t * pGate; + int nTwinOutputs = 0; + if ( pLib == NULL ) + return 0; + Mio_LibraryForEachGate( pLib, pGate ) + nTwinOutputs += (Mio_GateReadTwin(pGate) != NULL); + return nTwinOutputs / 2; +} + +/**Function************************************************************* + + Synopsis [Runs the ABC-native exact mapper.] + +***********************************************************************/ +int Emap_Command( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc); + Mio_Library_t * pLib = (Mio_Library_t *)Abc_FrameReadLibGen(); + Abc_Ntk_t * pNtkRes; + int c, fUseMogs = 1, fAreaMode = 0, fVerbose = 0; + + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "amvh" ) ) != EOF ) + { + switch ( c ) + { + case 'a': + fAreaMode ^= 1; + break; + case 'm': + fUseMogs ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( argc != globalUtilOptind ) + goto usage; + + if ( pNtk == NULL ) + { + fprintf( pAbc->Err, "There is no current network.\n" ); + return 1; + } + if ( pLib == NULL ) + { + fprintf( pAbc->Err, "There is no current GENLIB library. Use read_genlib/read_lib first.\n" ); + return 1; + } + if ( !Abc_NtkIsStrash(pNtk) ) + { + fprintf( pAbc->Err, "The current network is not an AIG. Run strash first.\n" ); + return 1; + } + + if ( fVerbose ) + { + int nMogPairs = fUseMogs ? Emap_CommandCountMogPairs( pLib ) : 0; + fprintf( pAbc->Out, "ABC-native emap setup: PI = %d PO = %d AND = %d\n", + Abc_NtkPiNum(pNtk), Abc_NtkPoNum(pNtk), Abc_NtkNodeNum(pNtk) ); + fprintf( pAbc->Out, "GENLIB \"%s\": gates = %d MOG pairs = %d MOG use = %s mode = %s\n", + Mio_LibraryReadName(pLib), Mio_LibraryReadGateNum(pLib), nMogPairs, fUseMogs ? "yes" : "no", fAreaMode ? "area" : "delay" ); + } + + pNtkRes = Emap_ManMapAigStructural( pNtk, pLib, fUseMogs, fAreaMode, fVerbose ); + if ( pNtkRes == NULL ) + { + fprintf( pAbc->Err, "ABC-native emap structural mapping has failed.\n" ); + return 1; + } + + Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes ); + return 0; + +usage: + fprintf( pAbc->Err, "usage: emap [-amvh]\n" ); + fprintf( pAbc->Err, "\t maps the current AIG using the current GENLIB library\n" ); + fprintf( pAbc->Err, "\t-a : toggle area-oriented mode without required-time pruning [default = %s]\n", fAreaMode ? "yes" : "no" ); + fprintf( pAbc->Err, "\t-m : toggle using multi-output gates when present [default = %s]\n", fUseMogs ? "yes" : "no" ); + fprintf( pAbc->Err, "\t-v : toggle verbose output [default = %s]\n", fVerbose ? "yes" : "no" ); + fprintf( pAbc->Err, "\t-h : prints the command summary\n\n" ); + fprintf( pAbc->Err, "\tThe mapper is inspired by \"emap\" in Mockturtle developed by Alessandro Tempia Calvino\n" ); + fprintf( pAbc->Err, "\tavailable at https://mockturtle.readthedocs.io/en/latest/algorithms/mapper.html\n" ); + fprintf( pAbc->Err, "\tand described in A. T. Calvino and G. De Micheli, \"Technology mapping using multi-output\n" ); + fprintf( pAbc->Err, "\tlibrary cells\", Proc. ICCAD\'23, https://aletempiac.github.io/publication/2023_006\n" ); + return 1; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END diff --git a/src/map/emap/emap.h b/src/map/emap/emap.h new file mode 100644 index 000000000..a326d3ed2 --- /dev/null +++ b/src/map/emap/emap.h @@ -0,0 +1,31 @@ +/**CFile**************************************************************** + + FileName [emap.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Multi-output gate mapper.] + + Synopsis [External declarations.] + +***********************************************************************/ + +#ifndef ABC__map__emap__emap_h +#define ABC__map__emap__emap_h + +#include "base/main/main.h" + +ABC_NAMESPACE_HEADER_START + +typedef struct Abc_Ntk_t_ Abc_Ntk_t; +typedef struct Mio_LibraryStruct_t_ Mio_Library_t; + +extern void Emap_Init ( Abc_Frame_t * pAbc ); +extern void Emap_End ( Abc_Frame_t * pAbc ); +extern int Emap_Command( Abc_Frame_t * pAbc, int argc, char ** argv ); + +extern Abc_Ntk_t * Emap_ManMapAigStructural( Abc_Ntk_t * pNtk, Mio_Library_t * pLib, int fUseMogs, int fAreaMode, int fVerbose ); + +ABC_NAMESPACE_HEADER_END + +#endif diff --git a/src/map/emap/emapCore.c b/src/map/emap/emapCore.c new file mode 100644 index 000000000..110951940 --- /dev/null +++ b/src/map/emap/emapCore.c @@ -0,0 +1,2662 @@ +/**CFile**************************************************************** + + FileName [emapCore.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Multi-output gate mapper.] + + Synopsis [Initial mapping core.] + +***********************************************************************/ + +#include "emap.h" + +#include "base/abc/abc.h" +#include "map/mio/mio.h" +#include "misc/extra/extra.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define EMAP_LEAF_MAX 6 +#define EMAP_CUT_MAX 128 +#define EMAP_FLOAT_LARGE ((float)1.0e20) +#define EMAP_DOUBLE_LARGE ((double)1.0e20) +#define EMAP_DELAY_EPS 0.1 + +typedef struct Emap_Cut_t_ Emap_Cut_t; +typedef struct Emap_Best_t_ Emap_Best_t; +typedef struct Emap_Obj_t_ Emap_Obj_t; +typedef struct Emap_Cell_t_ Emap_Cell_t; +typedef struct Emap_Mog_t_ Emap_Mog_t; +typedef struct Emap_PackEntry_t_ Emap_PackEntry_t; +typedef struct Emap_Tuple_t_ Emap_Tuple_t; +typedef struct Emap_Tuples_t_ Emap_Tuples_t; +typedef struct Emap_Lib_t_ Emap_Lib_t; + +struct Emap_Cut_t_ +{ + int nLeaves; + int Leaves[EMAP_LEAF_MAX]; + word Truth; +}; + +struct Emap_Best_t_ +{ + Mio_Gate_t * pGate; + int Cut; + int nPins; + int PinToLeaf[EMAP_LEAF_MAX]; + int PinPhase[EMAP_LEAF_MAX]; + int TwinObj; + int TwinPhase; + int fInv; + double Arr; + float Flow; +}; + +struct Emap_Obj_t_ +{ + int nCuts; + Emap_Cut_t Cuts[EMAP_CUT_MAX]; + Emap_Best_t Best[2]; +}; + +struct Emap_Cell_t_ +{ + Mio_Gate_t * pGate; + int nPins; + int PinToLeaf[EMAP_LEAF_MAX]; + int PinPhase[EMAP_LEAF_MAX]; + word Truth; + float Area; + float Delay[EMAP_LEAF_MAX]; +}; + +struct Emap_Mog_t_ +{ + Mio_Gate_t * pGate0; + Mio_Gate_t * pGate1; + int nPins; + int PinToLeaf[EMAP_LEAF_MAX]; + int PinPhase[EMAP_LEAF_MAX]; + word Truth0; + word Truth1; + float Area; + float Delay0[EMAP_LEAF_MAX]; + float Delay1[EMAP_LEAF_MAX]; +}; + +struct Emap_PackEntry_t_ +{ + int ObjId; + int Phase; + int Cut; + int nLeaves; + int Leaves[EMAP_LEAF_MAX]; + word Truth; +}; + +struct Emap_Tuple_t_ +{ + int Obj0; + int Phase0; + int Cut0; + int Obj1; + int Phase1; + int Cut1; + int Mog; + int fSwap; + int NextHigh; + int NextLow; +}; + +struct Emap_Tuples_t_ +{ + Emap_Tuple_t * pArray; + int nSize; + int nCap; + int * pFirstHigh; + int * pFirstLow; + int nAreaCalls; + int nAreaCandidates; + int nAreaRejectTwin; + int nAreaRejectRequired; + int nAreaRejectFlow; + int nAreaAccepts; + int nAreaSamples; + int nExactLocalCalls; + int nExactLocalCandidates; + int nExactLocalRejectUnused; + int nExactLocalRejectTwin; + int nExactLocalRejectShared; + int nExactLocalRejectRequired; + int nExactLocalRejectArea; + int nExactLocalAccepts; + int nExactLocalCand2; + int nExactLocalCand3; + int nExactLocalAccept2; + int nExactLocalAccept3; +}; + +struct Emap_Lib_t_ +{ + Emap_Cell_t * pCells; + int nCells; + int nCap; + Emap_Mog_t * pMogs; + int nMogs; + int nMogCap; + Mio_Gate_t * pGateInv; + float InvArea; + float InvDelay; +}; + +static Abc_Obj_t * Emap_ManCreateInv ( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pFanin, Mio_Gate_t * pGateInv ); +static Abc_Obj_t * Emap_ManBuildPhase_rec ( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew, Emap_Obj_t * pMaps, Vec_Int_t * vCopy, int ObjId, int Phase, Emap_Lib_t * pLib ); +static int Emap_ObjPairHasDirectDanglingRelation( Abc_Ntk_t * pNtk, int ObjId0, int ObjId1 ); +static int Emap_ObjPairHasTfiRelation( Abc_Ntk_t * pNtk, int ObjId0, int ObjId1 ); +static int Emap_ObjPairHasMffcDanglingRelation( Abc_Ntk_t * pNtk, int ObjId0, int ObjId1, Emap_Cut_t * pCut, char * pLeafMarks, int * pDecs, Vec_Int_t * vTouched ); +static double Emap_MogArrival ( Emap_Obj_t * pMaps, Emap_Cut_t * pCut, Emap_Mog_t * pMog, int fSwap ); +static void Emap_MogApply ( Emap_Obj_t * pMaps, Emap_PackEntry_t * pEntry0, Emap_PackEntry_t * pEntry1, Emap_Mog_t * pMog, int fSwap ); +static void Emap_MogSetOppositePhase( Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int ObjId, int Phase, float Flow ); +static int Emap_NodeMatchMogExactLocal( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Emap_Tuples_t * pTuples, int * pRefs, double * pRequired, Vec_Int_t * vTouched, int ObjId ); +static float Emap_ManComputeActualMappedStats( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Mio_Library_t * pMio, double * pDelay ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +static inline word Emap_TruthMask( int nVars ) +{ + return nVars == 6 ? ~(word)0 : (((word)1) << (1 << nVars)) - 1; +} + +static inline word Emap_TruthVar( int Var, int nVars ) +{ + word t = 0; + int m; + assert( Var < nVars ); + for ( m = 0; m < (1 << nVars); m++ ) + if ( (m >> Var) & 1 ) + t |= ((word)1) << m; + return t; +} + +static word Emap_TruthStretch( word Truth, int * pLeaves, int nLeaves, int * pLeavesNew, int nLeavesNew ) +{ + word Res = 0; + int m, i, k, mOld; + assert( nLeaves <= nLeavesNew ); + for ( m = 0; m < (1 << nLeavesNew); m++ ) + { + mOld = 0; + for ( i = 0; i < nLeaves; i++ ) + { + for ( k = 0; k < nLeavesNew; k++ ) + if ( pLeaves[i] == pLeavesNew[k] ) + break; + assert( k < nLeavesNew ); + if ( (m >> k) & 1 ) + mOld |= 1 << i; + } + if ( (Truth >> mOld) & 1 ) + Res |= ((word)1) << m; + } + return Res; +} + +static word Emap_TruthPermutePhase( word Truth, int nVars, int * pPinToLeaf, int * pPinPhase ) +{ + word Res = 0; + int m, i, mOld, Bit; + for ( m = 0; m < (1 << nVars); m++ ) + { + mOld = 0; + for ( i = 0; i < nVars; i++ ) + { + Bit = (m >> pPinToLeaf[i]) & 1; + if ( pPinPhase[i] ) + Bit ^= 1; + if ( Bit ) + mOld |= 1 << i; + } + if ( (Truth >> mOld) & 1 ) + Res |= ((word)1) << m; + } + return Res; +} + +static word Emap_TruthShrink6( word Truth, int nVars ) +{ + word Res = 0; + int m; + assert( nVars <= 6 ); + for ( m = 0; m < (1 << nVars); m++ ) + if ( (Truth >> m) & 1 ) + Res |= ((word)1) << m; + return Res; +} + +/**Function************************************************************* + + Synopsis [Creates a mapped inverter node.] + +***********************************************************************/ +static Abc_Obj_t * Emap_ManCreateInv( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pFanin, Mio_Gate_t * pGateInv ) +{ + Abc_Obj_t * pObj; + assert( pGateInv != NULL ); + pObj = Abc_NtkCreateNode( pNtkNew ); + pObj->pData = pGateInv; + Abc_ObjAddFanin( pObj, pFanin ); + return pObj; +} + +static void Emap_BestClean( Emap_Best_t * pBest ) +{ + memset( pBest, 0, sizeof(Emap_Best_t) ); + pBest->Cut = -1; + pBest->TwinObj = -1; + pBest->TwinPhase = -1; + pBest->Arr = EMAP_DOUBLE_LARGE; + pBest->Flow = EMAP_FLOAT_LARGE; +} + +static int Emap_BestIsBetterDelay( double ArrNew, float FlowNew, Emap_Best_t * pBest ) +{ + if ( ArrNew < pBest->Arr - 0.0001 ) + return 1; + if ( ArrNew > pBest->Arr + 0.0001 ) + return 0; + return FlowNew < pBest->Flow - 0.0001; +} + +static int Emap_BestIsBetterArea( double ArrNew, float FlowNew, Emap_Best_t * pBest ) +{ + if ( FlowNew < pBest->Flow - 0.0001 ) + return 1; + if ( FlowNew > pBest->Flow + 0.0001 ) + return 0; + return ArrNew < pBest->Arr - 0.0001; +} + +static int Emap_CutEqual( Emap_Cut_t * pCut, int * pLeaves, int nLeaves, word Truth ) +{ + int i; + if ( pCut->nLeaves != nLeaves || pCut->Truth != Truth ) + return 0; + for ( i = 0; i < nLeaves; i++ ) + if ( pCut->Leaves[i] != pLeaves[i] ) + return 0; + return 1; +} + +static int Emap_CutInsert( Emap_Obj_t * pMap, int * pLeaves, int nLeaves, word Truth ) +{ + Emap_Cut_t * pCut; + int i, iWorst = -1, nWorst = -1; + Truth &= Emap_TruthMask( nLeaves ); + for ( i = 0; i < pMap->nCuts; i++ ) + if ( Emap_CutEqual( &pMap->Cuts[i], pLeaves, nLeaves, Truth ) ) + return 0; + if ( pMap->nCuts == EMAP_CUT_MAX ) + { + for ( i = 0; i < pMap->nCuts; i++ ) + if ( pMap->Cuts[i].nLeaves > nWorst ) + nWorst = pMap->Cuts[i].nLeaves, iWorst = i; + if ( nLeaves >= nWorst ) + return 0; + pCut = &pMap->Cuts[iWorst]; + } + else + pCut = &pMap->Cuts[pMap->nCuts++]; + pCut->nLeaves = nLeaves; + pCut->Truth = Truth; + for ( i = 0; i < nLeaves; i++ ) + pCut->Leaves[i] = pLeaves[i]; + return 1; +} + +static int Emap_CutMergeLeaves( Emap_Cut_t * pCut0, Emap_Cut_t * pCut1, int * pLeaves ) +{ + int i = 0, k = 0, nLeaves = 0; + while ( i < pCut0->nLeaves || k < pCut1->nLeaves ) + { + int Leaf; + if ( k == pCut1->nLeaves || (i < pCut0->nLeaves && pCut0->Leaves[i] < pCut1->Leaves[k]) ) + Leaf = pCut0->Leaves[i++]; + else if ( i == pCut0->nLeaves || pCut1->Leaves[k] < pCut0->Leaves[i] ) + Leaf = pCut1->Leaves[k++]; + else + { + Leaf = pCut0->Leaves[i]; + i++; + k++; + } + if ( nLeaves == EMAP_LEAF_MAX ) + return -1; + pLeaves[nLeaves++] = Leaf; + } + return nLeaves; +} + +static void Emap_NodeAddUnitCut( Emap_Obj_t * pMap, int ObjId ) +{ + int Leaves[1]; + Leaves[0] = ObjId; + Emap_CutInsert( pMap, Leaves, 1, Emap_TruthVar( 0, 1 ) ); +} + +static void Emap_NodeAddConstCut( Emap_Obj_t * pMap ) +{ + Emap_CutInsert( pMap, NULL, 0, 1 ); +} + +static void Emap_LibAddCell( Emap_Lib_t * p, Mio_Gate_t * pGate, int * pPinToLeaf, int * pPinPhase, word Truth ) +{ + Emap_Cell_t * pCell; + Mio_Pin_t * pPin; + int i; + if ( p->nCells == p->nCap ) + { + p->nCap = p->nCap ? 2 * p->nCap : 1024; + p->pCells = ABC_REALLOC( Emap_Cell_t, p->pCells, p->nCap ); + } + pCell = &p->pCells[p->nCells++]; + memset( pCell, 0, sizeof(Emap_Cell_t) ); + pCell->pGate = pGate; + pCell->nPins = Mio_GateReadPinNum( pGate ); + pCell->Truth = Truth; + pCell->Area = (float)Mio_GateReadArea( pGate ); + for ( i = 0; i < pCell->nPins; i++ ) + { + pCell->PinToLeaf[i] = pPinToLeaf[i]; + pCell->PinPhase[i] = pPinPhase[i]; + } + i = 0; + Mio_GateForEachPin( pGate, pPin ) + pCell->Delay[i++] = (float)Mio_PinReadDelayBlockMax( pPin ); +} + +static void Emap_LibAddMog( Emap_Lib_t * p, Mio_Gate_t * pGate0, Mio_Gate_t * pGate1, int * pPinToLeaf, int * pPinPhase, word Truth0, word Truth1 ) +{ + Emap_Mog_t * pMog; + Mio_Pin_t * pPin; + int i; + if ( p->nMogs == p->nMogCap ) + { + p->nMogCap = p->nMogCap ? 2 * p->nMogCap : 128; + p->pMogs = ABC_REALLOC( Emap_Mog_t, p->pMogs, p->nMogCap ); + } + pMog = &p->pMogs[p->nMogs++]; + memset( pMog, 0, sizeof(Emap_Mog_t) ); + pMog->pGate0 = pGate0; + pMog->pGate1 = pGate1; + pMog->nPins = Mio_GateReadPinNum( pGate0 ); + pMog->Truth0 = Truth0; + pMog->Truth1 = Truth1; + pMog->Area = (float)Mio_GateReadArea( pGate0 ); + for ( i = 0; i < pMog->nPins; i++ ) + { + pMog->PinToLeaf[i] = pPinToLeaf[i]; + pMog->PinPhase[i] = pPinPhase[i]; + } + i = 0; + Mio_GateForEachPin( pGate0, pPin ) + pMog->Delay0[i++] = (float)Mio_PinReadDelayBlockMax( pPin ); + i = 0; + Mio_GateForEachPin( pGate1, pPin ) + pMog->Delay1[i++] = (float)Mio_PinReadDelayBlockMax( pPin ); +} + +static void Emap_LibPermute_rec( Emap_Lib_t * p, Mio_Gate_t * pGate, int nPins, int iPin, int * pPinToLeaf, int * pUsed ) +{ + int i; + if ( iPin == nPins ) + { + word Truth = Emap_TruthShrink6( Mio_GateReadTruth(pGate), nPins ); + int PinPhase[EMAP_LEAF_MAX]; + int Phase; + for ( Phase = 0; Phase < (1 << nPins); Phase++ ) + { + for ( i = 0; i < nPins; i++ ) + PinPhase[i] = (Phase >> i) & 1; + Emap_LibAddCell( p, pGate, pPinToLeaf, PinPhase, Emap_TruthPermutePhase( Truth, nPins, pPinToLeaf, PinPhase ) ); + } + return; + } + for ( i = 0; i < nPins; i++ ) + { + if ( pUsed[i] ) + continue; + pUsed[i] = 1; + pPinToLeaf[iPin] = i; + Emap_LibPermute_rec( p, pGate, nPins, iPin + 1, pPinToLeaf, pUsed ); + pUsed[i] = 0; + } +} + +static void Emap_LibMogPermute_rec( Emap_Lib_t * p, Mio_Gate_t * pGate0, Mio_Gate_t * pGate1, int nPins, int iPin, int * pPinToLeaf, int * pUsed ) +{ + int i; + if ( iPin == nPins ) + { + word Truth0 = Emap_TruthShrink6( Mio_GateReadTruth(pGate0), nPins ); + word Truth1 = Emap_TruthShrink6( Mio_GateReadTruth(pGate1), nPins ); + int PinPhase[EMAP_LEAF_MAX]; + int Phase; + for ( Phase = 0; Phase < (1 << nPins); Phase++ ) + { + for ( i = 0; i < nPins; i++ ) + PinPhase[i] = (Phase >> i) & 1; + Emap_LibAddMog( p, pGate0, pGate1, pPinToLeaf, PinPhase, Emap_TruthPermutePhase( Truth0, nPins, pPinToLeaf, PinPhase ), Emap_TruthPermutePhase( Truth1, nPins, pPinToLeaf, PinPhase ) ); + } + return; + } + for ( i = 0; i < nPins; i++ ) + { + if ( pUsed[i] ) + continue; + pUsed[i] = 1; + pPinToLeaf[iPin] = i; + Emap_LibMogPermute_rec( p, pGate0, pGate1, nPins, iPin + 1, pPinToLeaf, pUsed ); + pUsed[i] = 0; + } +} + +static void Emap_LibFree( Emap_Lib_t * p ) +{ + ABC_FREE( p->pCells ); + ABC_FREE( p->pMogs ); +} + +static int Emap_CellCompare( void const * p0, void const * p1 ) +{ + Emap_Cell_t const * pCell0 = (Emap_Cell_t const *)p0; + Emap_Cell_t const * pCell1 = (Emap_Cell_t const *)p1; + if ( pCell0->nPins != pCell1->nPins ) + return pCell0->nPins - pCell1->nPins; + if ( pCell0->Truth < pCell1->Truth ) + return -1; + if ( pCell0->Truth > pCell1->Truth ) + return 1; + return 0; +} + +static int Emap_LibFindFirst( Emap_Lib_t * p, int nPins, word Truth ) +{ + int Beg = 0, End = p->nCells; + while ( Beg < End ) + { + int Mid = (Beg + End) >> 1; + Emap_Cell_t * pCell = &p->pCells[Mid]; + if ( pCell->nPins < nPins || (pCell->nPins == nPins && pCell->Truth < Truth) ) + Beg = Mid + 1; + else + End = Mid; + } + if ( Beg == p->nCells || p->pCells[Beg].nPins != nPins || p->pCells[Beg].Truth != Truth ) + return -1; + return Beg; +} + +static int Emap_LibPrepare( Emap_Lib_t * p, Mio_Library_t * pMio ) +{ + Mio_Gate_t * pGate; + int PinToLeaf[EMAP_LEAF_MAX], Used[EMAP_LEAF_MAX]; + memset( p, 0, sizeof(Emap_Lib_t) ); + p->pGateInv = Mio_LibraryReadInv( pMio ); + if ( p->pGateInv == NULL ) + { + printf( "Cannot find inverter gate in the current GENLIB library.\n" ); + return 0; + } + p->InvArea = (float)Mio_GateReadArea( p->pGateInv ); + p->InvDelay = Mio_GateReadPinNum(p->pGateInv) ? Mio_GateReadPinDelay( p->pGateInv, 0 ) : 0; + Mio_LibraryForEachGate( pMio, pGate ) + { + int nPins = Mio_GateReadPinNum( pGate ); + Mio_Gate_t * pTwin = Mio_GateReadTwin(pGate); + if ( nPins < 2 || nPins > EMAP_LEAF_MAX ) + continue; + if ( pTwin != NULL ) + { + if ( pGate > pTwin || Mio_GateReadPinNum(pTwin) != nPins ) + continue; + memset( Used, 0, sizeof(Used) ); + Emap_LibMogPermute_rec( p, pGate, pTwin, nPins, 0, PinToLeaf, Used ); + continue; + } + memset( Used, 0, sizeof(Used) ); + Emap_LibPermute_rec( p, pGate, nPins, 0, PinToLeaf, Used ); + } + qsort( p->pCells, p->nCells, sizeof(Emap_Cell_t), Emap_CellCompare ); + return 1; +} + +static int Emap_NodeMergeCuts( Emap_Obj_t * pMaps, Abc_Obj_t * pObj ) +{ + Emap_Obj_t * pMap = &pMaps[Abc_ObjId(pObj)]; + Emap_Obj_t * pMap0 = &pMaps[Abc_ObjFaninId0(pObj)]; + Emap_Obj_t * pMap1 = &pMaps[Abc_ObjFaninId1(pObj)]; + Emap_Cut_t * pCut0, * pCut1; + int Leaves[EMAP_LEAF_MAX]; + int i, k, nLeaves; + word Truth0, Truth1, Mask; + Emap_NodeAddUnitCut( pMap, Abc_ObjId(pObj) ); + for ( i = 0; i < pMap0->nCuts; i++ ) + for ( k = 0; k < pMap1->nCuts; k++ ) + { + pCut0 = &pMap0->Cuts[i]; + pCut1 = &pMap1->Cuts[k]; + nLeaves = Emap_CutMergeLeaves( pCut0, pCut1, Leaves ); + if ( nLeaves < 0 ) + continue; + Mask = Emap_TruthMask( nLeaves ); + Truth0 = Emap_TruthStretch( pCut0->Truth, pCut0->Leaves, pCut0->nLeaves, Leaves, nLeaves ); + Truth1 = Emap_TruthStretch( pCut1->Truth, pCut1->Leaves, pCut1->nLeaves, Leaves, nLeaves ); + if ( Abc_ObjFaninC0(pObj) ) Truth0 ^= Mask; + if ( Abc_ObjFaninC1(pObj) ) Truth1 ^= Mask; + Emap_CutInsert( pMap, Leaves, nLeaves, Truth0 & Truth1 ); + } + return pMap->nCuts > 1; +} + +static int Emap_BestIsBetterMode( double ArrNew, float FlowNew, Emap_Best_t * pBest, int fAreaMode ) +{ + return fAreaMode ? Emap_BestIsBetterArea( ArrNew, FlowNew, pBest ) : Emap_BestIsBetterDelay( ArrNew, FlowNew, pBest ); +} + +static void Emap_NodeMatch( Emap_Obj_t * pMaps, Emap_Obj_t * pMap, Emap_Lib_t * pLib, Abc_Obj_t * pObj, double * pRequired, int * pRefs ) +{ + Emap_Cut_t * pCut; + Emap_Cell_t * pCell; + word Mask; + int i, k, c, fCompl, fAreaMode = (pRequired != NULL); + Emap_BestClean( &pMap->Best[0] ); + Emap_BestClean( &pMap->Best[1] ); + for ( i = 0; i < pMap->nCuts; i++ ) + { + pCut = &pMap->Cuts[i]; + if ( pCut->nLeaves < 2 ) + continue; + Mask = Emap_TruthMask( pCut->nLeaves ); + for ( fCompl = 0; fCompl < 2; fCompl++ ) + { + c = Emap_LibFindFirst( pLib, pCut->nLeaves, fCompl ? (pCut->Truth ^ Mask) : pCut->Truth ); + if ( c < 0 ) + continue; + for ( ; c < pLib->nCells; c++ ) + { + double Arr = 0; + double Required = fAreaMode ? pRequired[2 * Abc_ObjId(pObj) + fCompl] : EMAP_DOUBLE_LARGE; + float Flow; + pCell = &pLib->pCells[c]; + if ( pCell->nPins != pCut->nLeaves || pCell->Truth != (fCompl ? (pCut->Truth ^ Mask) : pCut->Truth) ) + break; + Flow = pCell->Area; + for ( k = 0; k < pCut->nLeaves; k++ ) + { + Abc_Obj_t * pLeaf = Abc_NtkObj( pObj->pNtk, pCut->Leaves[pCell->PinToLeaf[k]] ); + Emap_Best_t * pLeafBest = &pMaps[Abc_ObjId(pLeaf)].Best[pCell->PinPhase[k]]; + int LeafPhase = pCell->PinPhase[k]; + float Div = (float)Abc_MaxInt( 1, pRefs ? pRefs[2 * Abc_ObjId(pLeaf) + LeafPhase] : Abc_ObjFanoutNum(pLeaf) ); + Arr = Abc_MaxDouble( Arr, pLeafBest->Arr + pCell->Delay[k] ); + Flow += pLeafBest->Flow / Div; + } + if ( Arr > Required + 0.001 ) + continue; + if ( Emap_BestIsBetterMode( Arr, Flow, &pMap->Best[fCompl], fAreaMode ) ) + { + pMap->Best[fCompl].pGate = pCell->pGate; + pMap->Best[fCompl].Cut = i; + pMap->Best[fCompl].nPins = pCell->nPins; + pMap->Best[fCompl].Arr = Arr; + pMap->Best[fCompl].Flow = Flow; + pMap->Best[fCompl].fInv = 0; + for ( k = 0; k < pCell->nPins; k++ ) + { + pMap->Best[fCompl].PinToLeaf[k] = pCell->PinToLeaf[k]; + pMap->Best[fCompl].PinPhase[k] = pCell->PinPhase[k]; + } + } + } + } + } + for ( fCompl = 0; fCompl < 2; fCompl++ ) + if ( pMap->Best[!fCompl].pGate && (!fAreaMode || pMap->Best[!fCompl].Arr + pLib->InvDelay <= pRequired[2 * Abc_ObjId(pObj) + fCompl] + 0.001) && Emap_BestIsBetterMode( pMap->Best[!fCompl].Arr + pLib->InvDelay, pMap->Best[!fCompl].Flow + pLib->InvArea, &pMap->Best[fCompl], fAreaMode ) ) + { + pMap->Best[fCompl] = pMap->Best[!fCompl]; + pMap->Best[fCompl].fInv = 1; + pMap->Best[fCompl].Arr += pLib->InvDelay; + pMap->Best[fCompl].Flow += pLib->InvArea; + } +} + +static void Emap_NodeDropPhaseArea( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, double * pRequired, int * pRefs, int ObjId ) +{ + Emap_Obj_t * pMap = &pMaps[ObjId]; + Emap_Best_t Best0 = pMap->Best[0]; + Emap_Best_t Best1 = pMap->Best[1]; + float Est0 = (float)Abc_MaxInt( 1, pRefs ? pRefs[2 * ObjId + 0] : Abc_ObjFanoutNum(Abc_NtkObj(pNtk, ObjId)) ); + float Est1 = (float)Abc_MaxInt( 1, pRefs ? pRefs[2 * ObjId + 1] : Abc_ObjFanoutNum(Abc_NtkObj(pNtk, ObjId)) ); + int fUse0, fUse1; + if ( Best0.pGate == NULL || Best1.pGate == NULL || Best0.fInv || Best1.fInv || Best0.TwinObj >= 0 || Best1.TwinObj >= 0 ) + return; + fUse0 = Best0.Arr + pLib->InvDelay <= pRequired[2 * ObjId + 1] + 0.001; + fUse1 = Best1.Arr + pLib->InvDelay <= pRequired[2 * ObjId + 0] + 0.001; + if ( !fUse0 && !fUse1 ) + return; + if ( fUse0 && fUse1 ) + { + float Cost0 = Best0.Flow / Est0 + pLib->InvArea; + float Cost1 = Best1.Flow / Est1 + pLib->InvArea; + if ( Cost0 < Cost1 - 0.001 ) + fUse1 = 0; + else if ( Cost1 < Cost0 - 0.001 ) + fUse0 = 0; + else if ( Best0.Arr + pLib->InvDelay <= Best1.Arr + pLib->InvDelay ) + fUse1 = 0; + else + fUse0 = 0; + } + if ( fUse0 ) + { + pMap->Best[1] = Best0; + pMap->Best[1].fInv = 1; + pMap->Best[1].TwinObj = -1; + pMap->Best[1].TwinPhase = -1; + pMap->Best[1].Arr = Best0.Arr + pLib->InvDelay; + pMap->Best[1].Flow = Best0.Flow + pLib->InvArea; + } + else + { + pMap->Best[0] = Best1; + pMap->Best[0].fInv = 1; + pMap->Best[0].TwinObj = -1; + pMap->Best[0].TwinPhase = -1; + pMap->Best[0].Arr = Best1.Arr + pLib->InvDelay; + pMap->Best[0].Flow = Best1.Flow + pLib->InvArea; + } +} + +static void Emap_RequiredUpdate( double * pRequired, int ObjId, int Phase, double Required ) +{ + if ( Required < pRequired[2 * ObjId + Phase] ) + pRequired[2 * ObjId + Phase] = Required; +} + +static void Emap_RequiredPropagatePhase( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, double * pRequired, int ObjId, int Phase ) +{ + Emap_Obj_t * pMap = &pMaps[ObjId]; + Emap_Best_t * pBest = &pMap->Best[Phase]; + Emap_Cut_t * pCut; + double Required = pRequired[2 * ObjId + Phase]; + int i; + if ( Required >= EMAP_DOUBLE_LARGE / 2 ) + return; + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) || Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + return; + if ( pBest->fInv ) + { + Emap_RequiredUpdate( pRequired, ObjId, !Phase, Required - pLib->InvDelay ); + return; + } + if ( pBest->pGate == NULL ) + return; + pCut = &pMap->Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Emap_RequiredUpdate( pRequired, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i], Required - Mio_GateReadPinDelay(pBest->pGate, i) ); +} + +static void Emap_RequiredPropagateUsedObj( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, double * pRequired, int * pRefs, int ObjId ) +{ + Emap_Obj_t * pMap = &pMaps[ObjId]; + Emap_Best_t * pBest; + Emap_Cut_t * pCut; + int Phase, i; + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) || Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + return; + for ( Phase = 0; Phase < 2; Phase++ ) + { + pBest = &pMap->Best[Phase]; + if ( pRefs[2 * ObjId + Phase] == 0 || !pBest->fInv || pRequired[2 * ObjId + Phase] >= EMAP_DOUBLE_LARGE / 2 ) + continue; + Emap_RequiredUpdate( pRequired, ObjId, !Phase, pRequired[2 * ObjId + Phase] - pLib->InvDelay ); + } + for ( Phase = 0; Phase < 2; Phase++ ) + { + pBest = &pMap->Best[Phase]; + if ( pBest->pGate == NULL || pBest->fInv || pRequired[2 * ObjId + Phase] >= EMAP_DOUBLE_LARGE / 2 ) + continue; + pCut = &pMap->Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Emap_RequiredUpdate( pRequired, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i], pRequired[2 * ObjId + Phase] - Mio_GateReadPinDelay(pBest->pGate, i) ); + } +} + +static double Emap_ManComputeRequired( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, double * pRequired ) +{ + Abc_Obj_t * pObj; + double DelayTarget = 0; + int i, Phase; + for ( i = 0; i < 2 * Abc_NtkObjNumMax(pNtk); i++ ) + pRequired[i] = EMAP_DOUBLE_LARGE; + Abc_NtkForEachPo( pNtk, pObj, i ) + { + Phase = Abc_ObjFaninC0(pObj); + DelayTarget = Abc_MaxDouble( DelayTarget, pMaps[Abc_ObjFaninId0(pObj)].Best[Phase].Arr ); + } + Abc_NtkForEachPo( pNtk, pObj, i ) + Emap_RequiredUpdate( pRequired, Abc_ObjFaninId0(pObj), Abc_ObjFaninC0(pObj), DelayTarget ); + Abc_NtkForEachNodeReverse( pNtk, pObj, i ) + { + if ( !Abc_AigNodeIsAnd(pObj) ) + continue; + Emap_RequiredPropagatePhase( pNtk, pMaps, pLib, pRequired, Abc_ObjId(pObj), 0 ); + Emap_RequiredPropagatePhase( pNtk, pMaps, pLib, pRequired, Abc_ObjId(pObj), 1 ); + } + return DelayTarget; +} + +static void Emap_ManComputeRequiredTarget( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, double * pRequired, int * pRefs, double DelayTarget ) +{ + Abc_Obj_t * pObj; + int i; + for ( i = 0; i < 2 * Abc_NtkObjNumMax(pNtk); i++ ) + pRequired[i] = EMAP_DOUBLE_LARGE; + Abc_NtkForEachPo( pNtk, pObj, i ) + Emap_RequiredUpdate( pRequired, Abc_ObjFaninId0(pObj), Abc_ObjFaninC0(pObj), DelayTarget ); + Abc_NtkForEachNodeReverse( pNtk, pObj, i ) + { + if ( !Abc_AigNodeIsAnd(pObj) ) + continue; + Emap_RequiredPropagateUsedObj( pNtk, pMaps, pLib, pRequired, pRefs, Abc_ObjId(pObj) ); + } +} + +static void Emap_RefPhase_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ) +{ + Emap_Obj_t * pMap = &pMaps[ObjId]; + Emap_Best_t * pBest = &pMap->Best[Phase]; + Emap_Cut_t * pCut; + int i; + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) || Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + return; + if ( pRefs[2 * ObjId + Phase]++ > 0 ) + return; + if ( pBest->fInv ) + { + Emap_RefPhase_rec( pNtk, pMaps, pLib, pRefs, ObjId, !Phase ); + return; + } + if ( pBest->pGate == NULL ) + return; + pCut = &pMap->Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Emap_RefPhase_rec( pNtk, pMaps, pLib, pRefs, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i] ); +} + +static void Emap_ManComputeRefs( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs ) +{ + Abc_Obj_t * pObj; + int i; + memset( pRefs, 0, sizeof(int) * 2 * Abc_NtkObjNumMax(pNtk) ); + Abc_NtkForEachPo( pNtk, pObj, i ) + Emap_RefPhase_rec( pNtk, pMaps, pLib, pRefs, Abc_ObjFaninId0(pObj), Abc_ObjFaninC0(pObj) ); +} + +static float Emap_ManComputeArea( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs ) +{ + Abc_Obj_t * pObj; + float Area = 0; + int i, f; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + Abc_AigForEachAnd( pNtk, pObj, i ) + { + for ( f = 0; f < 2; f++ ) + { + Emap_Best_t * pBest = &pMaps[Abc_ObjId(pObj)].Best[f]; + if ( pRefs[2 * Abc_ObjId(pObj) + f] == 0 ) + continue; + if ( pBest->TwinObj >= 0 && 2 * Abc_ObjId(pObj) + f > 2 * pBest->TwinObj + pBest->TwinPhase ) + continue; + Area += pBest->fInv ? pLib->InvArea : (float)Mio_GateReadArea(pBest->pGate); + } + } + return Area; +} + +static void Emap_ManSaveBests( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Best_t * pSave ) +{ + int i; + for ( i = 0; i < Abc_NtkObjNumMax(pNtk); i++ ) + { + pSave[2 * i + 0] = pMaps[i].Best[0]; + pSave[2 * i + 1] = pMaps[i].Best[1]; + } +} + +static void Emap_ManRestoreBests( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Best_t * pSave ) +{ + int i; + for ( i = 0; i < Abc_NtkObjNumMax(pNtk); i++ ) + { + pMaps[i].Best[0] = pSave[2 * i + 0]; + pMaps[i].Best[1] = pSave[2 * i + 1]; + } +} + +static float Emap_PhaseRefVisit_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase ); +static float Emap_PhaseRef_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ); +static float Emap_PhaseDeref_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ); + +static float Emap_CutRefLeaves_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ) +{ + Emap_Best_t * pBest = &pMaps[ObjId].Best[Phase]; + Emap_Cut_t * pCut; + float Area; + int i; + if ( pBest->pGate == NULL && !pBest->fInv ) + return 0; + if ( pBest->fInv ) + return pLib->InvArea + Emap_PhaseRef_rec( pNtk, pMaps, pLib, pRefs, ObjId, !Phase ); + Area = (float)Mio_GateReadArea( pBest->pGate ); + pCut = &pMaps[ObjId].Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Area += Emap_PhaseRef_rec( pNtk, pMaps, pLib, pRefs, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i] ); + return Area; +} + +static float Emap_CutDerefLeaves_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ) +{ + Emap_Best_t * pBest = &pMaps[ObjId].Best[Phase]; + Emap_Cut_t * pCut; + float Area; + int i; + if ( pBest->pGate == NULL && !pBest->fInv ) + return 0; + if ( pBest->fInv ) + return pLib->InvArea + Emap_PhaseDeref_rec( pNtk, pMaps, pLib, pRefs, ObjId, !Phase ); + Area = (float)Mio_GateReadArea( pBest->pGate ); + pCut = &pMaps[ObjId].Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Area += Emap_PhaseDeref_rec( pNtk, pMaps, pLib, pRefs, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i] ); + return Area; +} + +static float Emap_CutRefOnlyLeaves_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ) +{ + Emap_Best_t * pBest = &pMaps[ObjId].Best[Phase]; + Emap_Cut_t * pCut; + float Area = 0; + int i; + if ( pBest->pGate == NULL && !pBest->fInv ) + return 0; + if ( pBest->fInv ) + return pLib->InvArea + Emap_PhaseRef_rec( pNtk, pMaps, pLib, pRefs, ObjId, !Phase ); + pCut = &pMaps[ObjId].Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Area += Emap_PhaseRef_rec( pNtk, pMaps, pLib, pRefs, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i] ); + return Area; +} + +static float Emap_PhaseRef_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ) +{ + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) || Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + return 0; + if ( pRefs[2 * ObjId + Phase]++ > 0 ) + return 0; + return Emap_CutRefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); +} + +static float Emap_PhaseDeref_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, int ObjId, int Phase ) +{ + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) || Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + return 0; + assert( pRefs[2 * ObjId + Phase] > 0 ); + if ( --pRefs[2 * ObjId + Phase] > 0 ) + return 0; + return Emap_CutDerefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); +} + +static float Emap_CutRefVisitLeaves_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase ) +{ + Emap_Best_t * pBest = &pMaps[ObjId].Best[Phase]; + Emap_Cut_t * pCut; + float Area; + int i; + if ( pBest->pGate == NULL && !pBest->fInv ) + return 0; + if ( pBest->fInv ) + return pLib->InvArea + Emap_PhaseRefVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, ObjId, !Phase ); + Area = (float)Mio_GateReadArea( pBest->pGate ); + pCut = &pMaps[ObjId].Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Area += Emap_PhaseRefVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i] ); + return Area; +} + +static float Emap_CutRefOnlyLeavesVisit_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase ) +{ + Emap_Best_t * pBest = &pMaps[ObjId].Best[Phase]; + Emap_Cut_t * pCut; + float Area = 0; + int i; + if ( pBest->pGate == NULL && !pBest->fInv ) + return 0; + if ( pBest->fInv ) + return pLib->InvArea + Emap_PhaseRefVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, ObjId, !Phase ); + pCut = &pMaps[ObjId].Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Area += Emap_PhaseRefVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i] ); + return Area; +} + +static float Emap_PhaseRefVisit_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase ) +{ + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) || Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + return 0; + Vec_IntPush( vTouched, 2 * ObjId + Phase ); + if ( pRefs[2 * ObjId + Phase]++ > 0 ) + return 0; + return Emap_CutRefVisitLeaves_rec( pNtk, pMaps, pLib, pRefs, vTouched, ObjId, Phase ); +} + +static float Emap_CutMeasureCandidate( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, Emap_Cut_t * pCut, Emap_Cell_t * pCell ) +{ + float Area = pCell->Area; + int i, Entry; + Vec_IntClear( vTouched ); + for ( i = 0; i < pCell->nPins; i++ ) + Area += Emap_PhaseRefVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, pCut->Leaves[pCell->PinToLeaf[i]], pCell->PinPhase[i] ); + Vec_IntForEachEntryReverse( vTouched, Entry, i ) + pRefs[Entry]--; + return Area; +} + +static void Emap_NodeRefreshInverterPhase( Emap_Obj_t * pMap, Emap_Lib_t * pLib, int Phase ) +{ + if ( !pMap->Best[Phase].fInv ) + return; + pMap->Best[Phase] = pMap->Best[!Phase]; + pMap->Best[Phase].fInv = 1; + pMap->Best[Phase].Arr += pLib->InvDelay; + pMap->Best[Phase].Flow += pLib->InvArea; +} + +static int Emap_NodeImproveExactPhase( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, double * pRequired, Vec_Int_t * vTouched, int ObjId, int Phase, int fRelaxArrival ) +{ + Emap_Obj_t * pMap = &pMaps[ObjId]; + Emap_Best_t OldBest = pMap->Best[Phase]; + Emap_Best_t BestBest = OldBest; + Emap_Cut_t * pCut; + Emap_Cell_t * pCell; + word Mask; + float AreaOld, AreaBest, AreaCand; + double Required, ArrBest, ArrCand; + int i, k, c, fCompl, fChanged = 0; + if ( pRefs[2 * ObjId + Phase] == 0 ) + return 0; + if ( OldBest.pGate == NULL || OldBest.fInv || OldBest.TwinObj >= 0 ) + return 0; + Required = pRequired[2 * ObjId + Phase]; + if ( Required >= EMAP_DOUBLE_LARGE / 2 ) + return 0; + AreaOld = Emap_CutDerefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); + AreaBest = AreaOld; + ArrBest = OldBest.Arr; + for ( i = 0; i < pMap->nCuts; i++ ) + { + pCut = &pMap->Cuts[i]; + if ( pCut->nLeaves < 2 ) + continue; + Mask = Emap_TruthMask( pCut->nLeaves ); + for ( fCompl = 0; fCompl < 2; fCompl++ ) + { + if ( fCompl != Phase ) + continue; + c = Emap_LibFindFirst( pLib, pCut->nLeaves, fCompl ? (pCut->Truth ^ Mask) : pCut->Truth ); + if ( c < 0 ) + continue; + for ( ; c < pLib->nCells; c++ ) + { + pCell = &pLib->pCells[c]; + if ( pCell->nPins != pCut->nLeaves || pCell->Truth != (fCompl ? (pCut->Truth ^ Mask) : pCut->Truth) ) + break; + ArrCand = 0; + for ( k = 0; k < pCell->nPins; k++ ) + ArrCand = Abc_MaxDouble( ArrCand, pMaps[pCut->Leaves[pCell->PinToLeaf[k]]].Best[pCell->PinPhase[k]].Arr + pCell->Delay[k] ); + if ( ArrCand > Required + 0.001 ) + continue; + if ( !fRelaxArrival && ArrCand > OldBest.Arr + 0.001 ) + continue; + AreaCand = Emap_CutMeasureCandidate( pNtk, pMaps, pLib, pRefs, vTouched, ObjId, pCut, pCell ); + if ( AreaCand < AreaBest - 0.001 || (AreaCand < AreaBest + 0.001 && ArrCand < ArrBest - 0.001) ) + { + Emap_BestClean( &BestBest ); + BestBest.pGate = pCell->pGate; + BestBest.Cut = i; + BestBest.nPins = pCell->nPins; + BestBest.Arr = ArrCand; + BestBest.Flow = AreaCand; + BestBest.fInv = 0; + for ( k = 0; k < pCell->nPins; k++ ) + { + BestBest.PinToLeaf[k] = pCell->PinToLeaf[k]; + BestBest.PinPhase[k] = pCell->PinPhase[k]; + } + AreaBest = AreaCand; + ArrBest = ArrCand; + } + } + } + } + fChanged = (BestBest.pGate != OldBest.pGate || BestBest.Cut != OldBest.Cut || memcmp( BestBest.PinToLeaf, OldBest.PinToLeaf, sizeof(int) * EMAP_LEAF_MAX ) || memcmp( BestBest.PinPhase, OldBest.PinPhase, sizeof(int) * EMAP_LEAF_MAX )); + pMap->Best[Phase] = BestBest; + Emap_CutRefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); + return fChanged; +} + +static int Emap_NodeDropPhaseExact( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, double * pRequired, int ObjId, int Phase ) +{ + Emap_Obj_t * pMap = &pMaps[ObjId]; + Emap_Best_t OldBest = pMap->Best[Phase]; + Emap_Best_t SrcBest = pMap->Best[!Phase]; + float AreaOld, AreaNew; + if ( pRefs[2 * ObjId + Phase] == 0 ) + return 0; + if ( SrcBest.pGate == NULL || SrcBest.fInv || SrcBest.TwinObj >= 0 ) + return 0; + if ( SrcBest.Arr + pLib->InvDelay > pRequired[2 * ObjId + Phase] + 0.001 ) + return 0; + AreaOld = Emap_CutDerefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); + pMap->Best[Phase] = SrcBest; + pMap->Best[Phase].fInv = 1; + pMap->Best[Phase].TwinObj = -1; + pMap->Best[Phase].TwinPhase = -1; + pMap->Best[Phase].Arr = SrcBest.Arr + pLib->InvDelay; + pMap->Best[Phase].Flow = SrcBest.Flow + pLib->InvArea; + AreaNew = Emap_CutRefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); + if ( AreaNew < AreaOld - 0.001 ) + return 1; + Emap_CutDerefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); + pMap->Best[Phase] = OldBest; + Emap_CutRefLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); + return 0; +} + +static int Emap_ObjSharedPhase( Emap_Obj_t * pMaps, int * pRefs, int ObjId ) +{ + Emap_Best_t * pBest0 = &pMaps[ObjId].Best[0]; + Emap_Best_t * pBest1 = &pMaps[ObjId].Best[1]; + if ( pBest0->fInv && !pBest1->fInv && pBest1->pGate != NULL && pBest1->TwinObj < 0 ) + return 1; + if ( pBest1->fInv && !pBest0->fInv && pBest0->pGate != NULL && pBest0->TwinObj < 0 ) + return 0; + if ( pRefs[2 * ObjId] && !pRefs[2 * ObjId + 1] && !pBest0->fInv && pBest0->pGate != NULL && pBest0->TwinObj < 0 ) + return 0; + if ( pRefs[2 * ObjId + 1] && !pRefs[2 * ObjId] && !pBest1->fInv && pBest1->pGate != NULL && pBest1->TwinObj < 0 ) + return 1; + return -1; +} + +static float Emap_CutDerefLeavesLocal_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase ); + +static float Emap_PhaseDerefLocal_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase ) +{ + int Entry = 2 * ObjId + Phase; + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) || Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + return 0; + if ( pRefs[Entry] == 0 ) + return 0; + Vec_IntPush( vTouched, Entry ); + if ( --pRefs[Entry] > 0 ) + return 0; + return Emap_CutDerefLeavesLocal_rec( pNtk, pMaps, pLib, pRefs, vTouched, ObjId, Phase ); +} + +static float Emap_CutDerefLeavesLocal_rec( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase ) +{ + Emap_Best_t * pBest = &pMaps[ObjId].Best[Phase]; + Emap_Cut_t * pCut; + float Area; + int i; + if ( pBest->pGate == NULL && !pBest->fInv ) + return 0; + if ( pBest->fInv ) + return pLib->InvArea + Emap_PhaseDerefLocal_rec( pNtk, pMaps, pLib, pRefs, vTouched, ObjId, !Phase ); + Area = (float)Mio_GateReadArea( pBest->pGate ); + pCut = &pMaps[ObjId].Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + Area += Emap_PhaseDerefLocal_rec( pNtk, pMaps, pLib, pRefs, vTouched, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i] ); + return Area; +} + +static float Emap_MogRefLeavesForUsedPhases( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int * pRefs, Vec_Int_t * vTouched, int ObjId, int Phase, int fVisit ) +{ + float Area = 0; + if ( pRefs[2 * ObjId + Phase] || pRefs[2 * ObjId + !Phase] ) + { + if ( fVisit ) + Area += Emap_CutRefOnlyLeavesVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, ObjId, Phase ); + else + Area += Emap_CutRefOnlyLeaves_rec( pNtk, pMaps, pLib, pRefs, ObjId, Phase ); + } + if ( pRefs[2 * ObjId + !Phase] ) + Area += pLib->InvArea; + return Area; +} + +static int Emap_NodeMatchMogExactLocal( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Emap_Tuples_t * pTuples, int * pRefs, double * pRequired, Vec_Int_t * vTouched, int ObjId ) +{ + int iTuple, nChanged = 0; + if ( pTuples == NULL || pTuples->pFirstLow == NULL ) + return 0; + pTuples->nExactLocalCalls++; + for ( iTuple = pTuples->pFirstLow[ObjId]; iTuple >= 0; iTuple = pTuples->pArray[iTuple].NextLow ) + { + Emap_Tuple_t * pTuple = &pTuples->pArray[iTuple]; + Emap_Mog_t * pMog = &pLib->pMogs[pTuple->Mog]; + Emap_PackEntry_t Entry0, Entry1; + Emap_Best_t OldBest00, OldBest01, OldBest10, OldBest11; + int Shared0, Shared1, Entry, t, fObj0Low, nDerefTouched; + float AreaOld, AreaNew; + double Arr0, Arr1; + int Obj0 = pTuple->Obj0, Obj1 = pTuple->Obj1; + int Used0 = pRefs[2 * Obj0] || pRefs[2 * Obj0 + 1]; + int Used1 = pRefs[2 * Obj1] || pRefs[2 * Obj1 + 1]; + pTuples->nExactLocalCandidates++; + if ( pMog->nPins == 2 ) + pTuples->nExactLocalCand2++; + else if ( pMog->nPins == 3 ) + pTuples->nExactLocalCand3++; + if ( !Used0 || !Used1 ) + { + pTuples->nExactLocalRejectUnused++; + continue; + } + if ( pMaps[Obj0].Best[0].TwinObj >= 0 || pMaps[Obj0].Best[1].TwinObj >= 0 || pMaps[Obj1].Best[0].TwinObj >= 0 || pMaps[Obj1].Best[1].TwinObj >= 0 ) + { + pTuples->nExactLocalRejectTwin++; + continue; + } + Shared0 = Emap_ObjSharedPhase( pMaps, pRefs, Obj0 ); + Shared1 = Emap_ObjSharedPhase( pMaps, pRefs, Obj1 ); + if ( Shared0 < 0 || Shared1 < 0 ) + { + pTuples->nExactLocalRejectShared++; + continue; + } + Arr0 = Emap_MogArrival( pMaps, &pMaps[Obj0].Cuts[pTuple->Cut0], pMog, pTuple->fSwap ); + Arr1 = Emap_MogArrival( pMaps, &pMaps[Obj1].Cuts[pTuple->Cut1], pMog, !pTuple->fSwap ); + if ( Arr0 > pRequired[2 * Obj0 + pTuple->Phase0] + 0.001 || Arr1 > pRequired[2 * Obj1 + pTuple->Phase1] + 0.001 ) + { + pTuples->nExactLocalRejectRequired++; + continue; + } + if ( pRefs[2 * Obj0 + !pTuple->Phase0] && Arr0 + pLib->InvDelay > pRequired[2 * Obj0 + !pTuple->Phase0] + 0.001 ) + { + pTuples->nExactLocalRejectRequired++; + continue; + } + if ( pRefs[2 * Obj1 + !pTuple->Phase1] && Arr1 + pLib->InvDelay > pRequired[2 * Obj1 + !pTuple->Phase1] + 0.001 ) + { + pTuples->nExactLocalRejectRequired++; + continue; + } + + OldBest00 = pMaps[Obj0].Best[0]; + OldBest01 = pMaps[Obj0].Best[1]; + OldBest10 = pMaps[Obj1].Best[0]; + OldBest11 = pMaps[Obj1].Best[1]; + fObj0Low = Obj0 < Obj1; + Vec_IntClear( vTouched ); + AreaOld = 0; + if ( fObj0Low ) + { + AreaOld += Emap_CutDerefLeavesLocal_rec( pNtk, pMaps, pLib, pRefs, vTouched, Obj1, Shared1 ); + AreaOld += pRefs[2 * Obj1 + !Shared1] ? pLib->InvArea : 0; + AreaOld += Emap_CutDerefLeavesLocal_rec( pNtk, pMaps, pLib, pRefs, vTouched, Obj0, Shared0 ); + AreaOld += pRefs[2 * Obj0 + !Shared0] ? pLib->InvArea : 0; + } + else + { + AreaOld += Emap_CutDerefLeavesLocal_rec( pNtk, pMaps, pLib, pRefs, vTouched, Obj0, Shared0 ); + AreaOld += pRefs[2 * Obj0 + !Shared0] ? pLib->InvArea : 0; + AreaOld += Emap_CutDerefLeavesLocal_rec( pNtk, pMaps, pLib, pRefs, vTouched, Obj1, Shared1 ); + AreaOld += pRefs[2 * Obj1 + !Shared1] ? pLib->InvArea : 0; + } + nDerefTouched = Vec_IntSize( vTouched ); + + memset( &Entry0, 0, sizeof(Entry0) ); + memset( &Entry1, 0, sizeof(Entry1) ); + Entry0.ObjId = Obj0; Entry0.Phase = pTuple->Phase0; Entry0.Cut = pTuple->Cut0; + Entry1.ObjId = Obj1; Entry1.Phase = pTuple->Phase1; Entry1.Cut = pTuple->Cut1; + Emap_MogApply( pMaps, &Entry0, &Entry1, pMog, pTuple->fSwap ); + Emap_MogSetOppositePhase( pMaps, pLib, Obj0, pTuple->Phase0, pMog->Area ); + Emap_MogSetOppositePhase( pMaps, pLib, Obj1, pTuple->Phase1, pMog->Area ); + + AreaNew = pMog->Area; + AreaNew += Emap_MogRefLeavesForUsedPhases( pNtk, pMaps, pLib, pRefs, vTouched, Obj0, pTuple->Phase0, 1 ); + AreaNew += Emap_MogRefLeavesForUsedPhases( pNtk, pMaps, pLib, pRefs, vTouched, Obj1, pTuple->Phase1, 1 ); + Vec_IntForEachEntryReverse( vTouched, Entry, t ) + { + if ( t < nDerefTouched ) + break; + pRefs[Entry]--; + } + + if ( AreaNew < AreaOld - 0.001 ) + { + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + pTuples->nExactLocalAccepts++; + if ( pMog->nPins == 2 ) + pTuples->nExactLocalAccept2++; + else if ( pMog->nPins == 3 ) + pTuples->nExactLocalAccept3++; + nChanged++; + break; + } + pTuples->nExactLocalRejectArea++; + + pMaps[Obj0].Best[0] = OldBest00; + pMaps[Obj0].Best[1] = OldBest01; + pMaps[Obj1].Best[0] = OldBest10; + pMaps[Obj1].Best[1] = OldBest11; + for ( t = 0; t < nDerefTouched; t++ ) + pRefs[Vec_IntEntry(vTouched, t)]++; + } + return nChanged; +} + +static int Emap_ManRecoverExactArea( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Emap_Tuples_t * pTuples, double * pRequired, int * pRefs, int nRounds, double DelayTarget, int fRelaxArrival, int fDropPhase ) +{ + Vec_Int_t * vTouched = Vec_IntAlloc( 1000 ); + Abc_Obj_t * pObj; + int i, r, f, nChanges = 0; + for ( r = 0; r < nRounds; r++ ) + { + int nChangesThis = 0; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + Emap_ManComputeRequiredTarget( pNtk, pMaps, pLib, pRequired, pRefs, DelayTarget ); + Abc_NtkForEachNodeReverse( pNtk, pObj, i ) + { + if ( !Abc_AigNodeIsAnd(pObj) ) + continue; + for ( f = 0; f < 2; f++ ) + nChangesThis += Emap_NodeImproveExactPhase( pNtk, pMaps, pLib, pRefs, pRequired, vTouched, Abc_ObjId(pObj), f, fRelaxArrival ); + Emap_NodeRefreshInverterPhase( &pMaps[Abc_ObjId(pObj)], pLib, 0 ); + Emap_NodeRefreshInverterPhase( &pMaps[Abc_ObjId(pObj)], pLib, 1 ); + if ( fDropPhase ) + { + nChangesThis += Emap_NodeDropPhaseExact( pNtk, pMaps, pLib, pRefs, pRequired, Abc_ObjId(pObj), 0 ); + nChangesThis += Emap_NodeDropPhaseExact( pNtk, pMaps, pLib, pRefs, pRequired, Abc_ObjId(pObj), 1 ); + } + if ( pTuples && getenv("ABC_EMAP_LOCAL_MOG_EXACT") ) + nChangesThis += Emap_NodeMatchMogExactLocal( pNtk, pMaps, pLib, pTuples, pRefs, pRequired, vTouched, Abc_ObjId(pObj) ); + Emap_RequiredPropagateUsedObj( pNtk, pMaps, pLib, pRequired, pRefs, Abc_ObjId(pObj) ); + } + nChanges += nChangesThis; + if ( nChangesThis == 0 ) + break; + } + Vec_IntFree( vTouched ); + return nChanges; +} + +static int Emap_PackEntryCompare( void const * p0, void const * p1 ) +{ + Emap_PackEntry_t const * pEntry0 = (Emap_PackEntry_t const *)p0; + Emap_PackEntry_t const * pEntry1 = (Emap_PackEntry_t const *)p1; + int i; + if ( pEntry0->nLeaves != pEntry1->nLeaves ) + return pEntry0->nLeaves - pEntry1->nLeaves; + if ( pEntry0->Truth < pEntry1->Truth ) + return -1; + if ( pEntry0->Truth > pEntry1->Truth ) + return 1; + for ( i = 0; i < pEntry0->nLeaves; i++ ) + if ( pEntry0->Leaves[i] != pEntry1->Leaves[i] ) + return pEntry0->Leaves[i] - pEntry1->Leaves[i]; + return 0; +} + +static int Emap_PackEntryFindFirst( Emap_PackEntry_t * pEntries, int nEntries, Emap_Cut_t * pCut, word Truth ) +{ + Emap_PackEntry_t Key; + int Beg = 0, End = nEntries, i; + memset( &Key, 0, sizeof(Key) ); + Key.nLeaves = pCut->nLeaves; + Key.Truth = Truth; + for ( i = 0; i < pCut->nLeaves; i++ ) + Key.Leaves[i] = pCut->Leaves[i]; + while ( Beg < End ) + { + int Mid = (Beg + End) >> 1; + if ( Emap_PackEntryCompare( &pEntries[Mid], &Key ) < 0 ) + Beg = Mid + 1; + else + End = Mid; + } + if ( Beg == nEntries || Emap_PackEntryCompare( &pEntries[Beg], &Key ) != 0 ) + return -1; + return Beg; +} + +static void Emap_TuplesFree( Emap_Tuples_t * p ) +{ + ABC_FREE( p->pArray ); + ABC_FREE( p->pFirstHigh ); + ABC_FREE( p->pFirstLow ); +} + +static void Emap_TuplesAdd( Emap_Tuples_t * p, int Obj0, int Phase0, int Cut0, int Obj1, int Phase1, int Cut1, int Mog, int fSwap ) +{ + Emap_Tuple_t * pTuple; + int High = Abc_MaxInt( Obj0, Obj1 ); + int Low = Abc_MinInt( Obj0, Obj1 ); + if ( p->nSize == p->nCap ) + { + p->nCap = p->nCap ? 2 * p->nCap : 1024; + p->pArray = ABC_REALLOC( Emap_Tuple_t, p->pArray, p->nCap ); + } + pTuple = &p->pArray[p->nSize]; + pTuple->Obj0 = Obj0; + pTuple->Phase0 = Phase0; + pTuple->Cut0 = Cut0; + pTuple->Obj1 = Obj1; + pTuple->Phase1 = Phase1; + pTuple->Cut1 = Cut1; + pTuple->Mog = Mog; + pTuple->fSwap = fSwap; + pTuple->NextHigh = p->pFirstHigh[High]; + pTuple->NextLow = p->pFirstLow[Low]; + p->pFirstHigh[High] = p->nSize; + p->pFirstLow[Low] = p->nSize++; +} + +static void Emap_ManComputeMogTuples( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Emap_Tuples_t * pTuples ) +{ + Emap_PackEntry_t * pEntries; + int * pAssign; + Vec_Int_t * vMffcTouched = NULL; + int * pDecs = NULL; + char * pLeafMarks = NULL; + Abc_Obj_t * pObj; + int i, k, f, nEntries = 0, nGroups = 0, fUseMffc = getenv("ABC_EMAP_MFFC_TUPLES") != NULL; + memset( pTuples, 0, sizeof(Emap_Tuples_t) ); + if ( pLib->nMogs == 0 ) + return; + pTuples->pFirstHigh = ABC_ALLOC( int, Abc_NtkObjNumMax(pNtk) ); + pTuples->pFirstLow = ABC_ALLOC( int, Abc_NtkObjNumMax(pNtk) ); + for ( i = 0; i < Abc_NtkObjNumMax(pNtk); i++ ) + { + pTuples->pFirstHigh[i] = -1; + pTuples->pFirstLow[i] = -1; + } + pEntries = ABC_ALLOC( Emap_PackEntry_t, 2 * EMAP_CUT_MAX * Abc_NtkObjNumMax(pNtk) ); + pAssign = ABC_ALLOC( int, Abc_NtkObjNumMax(pNtk) ); + for ( i = 0; i < Abc_NtkObjNumMax(pNtk); i++ ) + pAssign[i] = -1; + if ( fUseMffc ) + { + vMffcTouched = Vec_IntAlloc( 100 ); + pDecs = ABC_CALLOC( int, Abc_NtkObjNumMax(pNtk) ); + pLeafMarks = ABC_CALLOC( char, Abc_NtkObjNumMax(pNtk) ); + } + Abc_AigForEachAnd( pNtk, pObj, i ) + { + for ( f = 0; f < 2; f++ ) + { + Emap_Obj_t * pMap = &pMaps[Abc_ObjId(pObj)]; + int c; + for ( c = 0; c < pMap->nCuts; c++ ) + { + Emap_Cut_t * pCut = &pMap->Cuts[c]; + word Truth = f ? (pCut->Truth ^ Emap_TruthMask(pCut->nLeaves)) : pCut->Truth; + if ( pCut->nLeaves < 2 || pCut->nLeaves > 3 ) + continue; + pEntries[nEntries].ObjId = Abc_ObjId(pObj); + pEntries[nEntries].Phase = f; + pEntries[nEntries].Cut = c; + pEntries[nEntries].nLeaves = pCut->nLeaves; + pEntries[nEntries].Truth = Truth; + for ( k = 0; k < pCut->nLeaves; k++ ) + pEntries[nEntries].Leaves[k] = pCut->Leaves[k]; + nEntries++; + } + } + } + qsort( pEntries, nEntries, sizeof(Emap_PackEntry_t), Emap_PackEntryCompare ); + for ( i = nEntries - 1; i >= 0; i-- ) + { + Emap_PackEntry_t * pEntry0 = &pEntries[i]; + Emap_Cut_t * pCut0 = &pMaps[pEntry0->ObjId].Cuts[pEntry0->Cut]; + for ( k = 0; k < pLib->nMogs; k++ ) + { + Emap_Mog_t * pMog = &pLib->pMogs[k]; + int s; + if ( pMog->nPins != pCut0->nLeaves ) + continue; + for ( s = 0; s < 2; s++ ) + { + word Truth0 = s ? pMog->Truth1 : pMog->Truth0; + word Truth1 = s ? pMog->Truth0 : pMog->Truth1; + int Beg; + if ( Truth0 != pEntry0->Truth ) + continue; + Beg = Emap_PackEntryFindFirst( pEntries, nEntries, pCut0, Truth1 ); + if ( Beg < 0 ) + continue; + for ( ; Beg < nEntries && pEntries[Beg].nLeaves == pCut0->nLeaves && pEntries[Beg].Truth == Truth1; Beg++ ) + { + Emap_PackEntry_t * pEntry1 = &pEntries[Beg]; + int m, fSameLeaves = 1; + for ( m = 0; m < pCut0->nLeaves; m++ ) + if ( pEntry1->Leaves[m] != pCut0->Leaves[m] ) + fSameLeaves = 0; + if ( !fSameLeaves ) + break; + if ( pEntry1->ObjId == pEntry0->ObjId ) + continue; + if ( Emap_ObjPairHasDirectDanglingRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId ) ) + continue; + if ( fUseMffc ? Emap_ObjPairHasMffcDanglingRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId, pCut0, pLeafMarks, pDecs, vMffcTouched ) : Emap_ObjPairHasTfiRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId ) ) + continue; + if ( pAssign[pEntry0->ObjId] == -1 && pAssign[pEntry1->ObjId] == -1 ) + pAssign[pEntry0->ObjId] = pAssign[pEntry1->ObjId] = nGroups++; + else if ( pAssign[pEntry0->ObjId] != pAssign[pEntry1->ObjId] || pAssign[pEntry0->ObjId] == -1 ) + continue; + Emap_TuplesAdd( pTuples, pEntry0->ObjId, pEntry0->Phase, pEntry0->Cut, pEntry1->ObjId, pEntry1->Phase, pEntry1->Cut, k, s ); + } + } + } + } + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG tuple setup: tuples=%d groups=%d mode=%s\n", pTuples->nSize, nGroups, fUseMffc ? "mffc" : "strict" ); + ABC_FREE( pLeafMarks ); + ABC_FREE( pDecs ); + if ( vMffcTouched ) + Vec_IntFree( vMffcTouched ); + ABC_FREE( pAssign ); + ABC_FREE( pEntries ); +} + +static int Emap_ObjPairHasDirectDanglingRelation( Abc_Ntk_t * pNtk, int ObjId0, int ObjId1 ) +{ + Abc_Obj_t * pObj0 = Abc_NtkObj( pNtk, ObjId0 ); + Abc_Obj_t * pObj1 = Abc_NtkObj( pNtk, ObjId1 ); + if ( !Abc_ObjIsPi(pObj0) && !Abc_AigNodeIsConst(pObj0) && (Abc_ObjFaninId0(pObj0) == ObjId1 || Abc_ObjFaninId1(pObj0) == ObjId1) && Abc_ObjFanoutNum(pObj1) == 1 ) + return 1; + if ( !Abc_ObjIsPi(pObj1) && !Abc_AigNodeIsConst(pObj1) && (Abc_ObjFaninId0(pObj1) == ObjId0 || Abc_ObjFaninId1(pObj1) == ObjId0) && Abc_ObjFanoutNum(pObj0) == 1 ) + return 1; + return 0; +} + +static void Emap_MffcDeref_rec( Abc_Obj_t * pObj, char * pLeafMarks, int * pDecs, Vec_Int_t * vTouched ) +{ + Abc_Obj_t * pFanin; + int i, ObjId; + if ( Abc_ObjIsPi(pObj) || Abc_AigNodeIsConst(pObj) || pLeafMarks[Abc_ObjId(pObj)] ) + return; + Abc_ObjForEachFanin( pObj, pFanin, i ) + { + ObjId = Abc_ObjId(pFanin); + if ( pLeafMarks[ObjId] ) + continue; + if ( pDecs[ObjId]++ == 0 ) + Vec_IntPush( vTouched, ObjId ); + if ( pDecs[ObjId] == Abc_ObjFanoutNum(pFanin) ) + Emap_MffcDeref_rec( pFanin, pLeafMarks, pDecs, vTouched ); + } +} + +static int Emap_ObjPairHasMffcDanglingRelation( Abc_Ntk_t * pNtk, int ObjId0, int ObjId1, Emap_Cut_t * pCut, char * pLeafMarks, int * pDecs, Vec_Int_t * vTouched ) +{ + int Low = Abc_MinInt( ObjId0, ObjId1 ); + int High = Abc_MaxInt( ObjId0, ObjId1 ); + Abc_Obj_t * pLow = Abc_NtkObj( pNtk, Low ); + Abc_Obj_t * pHigh = Abc_NtkObj( pNtk, High ); + int i, Entry, fDangling; + assert( Vec_IntSize(vTouched) == 0 ); + if ( !Abc_ObjIsPi(pHigh) && !Abc_AigNodeIsConst(pHigh) && (Abc_ObjFaninId0(pHigh) == Low || Abc_ObjFaninId1(pHigh) == Low) && Abc_ObjFanoutNum(pLow) == 1 ) + return 1; + for ( i = 0; i < pCut->nLeaves; i++ ) + pLeafMarks[pCut->Leaves[i]] = 1; + Emap_MffcDeref_rec( pHigh, pLeafMarks, pDecs, vTouched ); + fDangling = Abc_ObjFanoutNum(pLow) - pDecs[Low] <= 0; + for ( i = 0; i < pCut->nLeaves; i++ ) + pLeafMarks[pCut->Leaves[i]] = 0; + Vec_IntForEachEntry( vTouched, Entry, i ) + pDecs[Entry] = 0; + Vec_IntClear( vTouched ); + return fDangling; +} + +static int Emap_ObjIsInTfi_rec( Abc_Obj_t * pRoot, int TargetId ) +{ + if ( Abc_ObjId(pRoot) == TargetId ) + return 1; + if ( Abc_ObjIsPi(pRoot) || Abc_AigNodeIsConst(pRoot) ) + return 0; + if ( Abc_NodeIsTravIdCurrent(pRoot) ) + return 0; + Abc_NodeSetTravIdCurrent(pRoot); + return Emap_ObjIsInTfi_rec( Abc_ObjFanin0(pRoot), TargetId ) || Emap_ObjIsInTfi_rec( Abc_ObjFanin1(pRoot), TargetId ); +} + +static int Emap_ObjPairHasTfiRelation( Abc_Ntk_t * pNtk, int ObjId0, int ObjId1 ) +{ + Abc_NtkIncrementTravId( pNtk ); + if ( Emap_ObjIsInTfi_rec( Abc_NtkObj(pNtk, ObjId0), ObjId1 ) ) + return 1; + Abc_NtkIncrementTravId( pNtk ); + return Emap_ObjIsInTfi_rec( Abc_NtkObj(pNtk, ObjId1), ObjId0 ); +} + +static double Emap_MogArrival( Emap_Obj_t * pMaps, Emap_Cut_t * pCut, Emap_Mog_t * pMog, int fSwap ); + +static void Emap_MogApply( Emap_Obj_t * pMaps, Emap_PackEntry_t * pEntry0, Emap_PackEntry_t * pEntry1, Emap_Mog_t * pMog, int fSwap ) +{ + Emap_Best_t * pBest0 = &pMaps[pEntry0->ObjId].Best[pEntry0->Phase]; + Emap_Best_t * pBest1 = &pMaps[pEntry1->ObjId].Best[pEntry1->Phase]; + Emap_Cut_t * pCut0 = &pMaps[pEntry0->ObjId].Cuts[pEntry0->Cut]; + Emap_Cut_t * pCut1 = &pMaps[pEntry1->ObjId].Cuts[pEntry1->Cut]; + int i; + pBest0->pGate = fSwap ? pMog->pGate1 : pMog->pGate0; + pBest1->pGate = fSwap ? pMog->pGate0 : pMog->pGate1; + pBest0->Cut = pEntry0->Cut; + pBest1->Cut = pEntry1->Cut; + pBest0->nPins = pBest1->nPins = pMog->nPins; + pBest0->TwinObj = pEntry1->ObjId; + pBest0->TwinPhase = pEntry1->Phase; + pBest1->TwinObj = pEntry0->ObjId; + pBest1->TwinPhase = pEntry0->Phase; + pBest0->fInv = pBest1->fInv = 0; + pBest0->Arr = Emap_MogArrival( pMaps, pCut0, pMog, fSwap ); + pBest1->Arr = Emap_MogArrival( pMaps, pCut1, pMog, !fSwap ); + pBest0->Flow = pBest1->Flow = pMog->Area; + for ( i = 0; i < pMog->nPins; i++ ) + { + pBest0->PinToLeaf[i] = pBest1->PinToLeaf[i] = pMog->PinToLeaf[i]; + pBest0->PinPhase[i] = pBest1->PinPhase[i] = pMog->PinPhase[i]; + } +} + +static double Emap_MogArrival( Emap_Obj_t * pMaps, Emap_Cut_t * pCut, Emap_Mog_t * pMog, int fSwap ) +{ + double Arr = 0; + int i; + for ( i = 0; i < pMog->nPins; i++ ) + { + Emap_Best_t * pLeafBest = &pMaps[pCut->Leaves[pMog->PinToLeaf[i]]].Best[pMog->PinPhase[i]]; + Arr = Abc_MaxDouble( Arr, pLeafBest->Arr + (fSwap ? pMog->Delay1[i] : pMog->Delay0[i]) ); + } + return Arr; +} + +static void Emap_MogSetOppositePhase( Emap_Obj_t * pMaps, Emap_Lib_t * pLib, int ObjId, int Phase, float Flow ) +{ + pMaps[ObjId].Best[!Phase] = pMaps[ObjId].Best[Phase]; + pMaps[ObjId].Best[!Phase].fInv = 1; + pMaps[ObjId].Best[!Phase].TwinObj = -1; + pMaps[ObjId].Best[!Phase].TwinPhase = -1; + pMaps[ObjId].Best[!Phase].Arr = pMaps[ObjId].Best[Phase].Arr + pLib->InvDelay; + pMaps[ObjId].Best[!Phase].Flow = Flow + pLib->InvArea; +} + +static int Emap_NodeMatchMogArea( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Emap_Tuples_t * pTuples, int * pRefs, double * pRequired, int ObjId, int fCheckRequired ) +{ + int iTuple, iBestTuple = -1; + float BestFlow = (float)EMAP_DOUBLE_LARGE, BestScore = (float)EMAP_DOUBLE_LARGE; + if ( pTuples == NULL || pTuples->pFirstHigh == NULL ) + return 0; + pTuples->nAreaCalls++; + for ( iTuple = pTuples->pFirstHigh[ObjId]; iTuple >= 0; iTuple = pTuples->pArray[iTuple].NextHigh ) + { + Emap_Tuple_t * pTuple = &pTuples->pArray[iTuple]; + Emap_Mog_t * pMog = &pLib->pMogs[pTuple->Mog]; + Emap_Cut_t * pCut0 = &pMaps[pTuple->Obj0].Cuts[pTuple->Cut0]; + Emap_Cut_t * pCut1 = &pMaps[pTuple->Obj1].Cuts[pTuple->Cut1]; + Emap_Best_t * pBest0 = &pMaps[pTuple->Obj0].Best[pTuple->Phase0]; + Emap_Best_t * pBest1 = &pMaps[pTuple->Obj1].Best[pTuple->Phase1]; + double Arr0, Arr1; + float OldFlow = 0, NewFlow, NewScore, LeafFlow = 0, CombinedRefs = 0; + int fRespectsRequired = 1; + int i; + pTuples->nAreaCandidates++; + if ( pBest0->TwinObj >= 0 || pBest1->TwinObj >= 0 ) + { + pTuples->nAreaRejectTwin++; + continue; + } + Arr0 = Emap_MogArrival( pMaps, pCut0, pMog, pTuple->fSwap ); + Arr1 = Emap_MogArrival( pMaps, pCut1, pMog, !pTuple->fSwap ); + if ( fCheckRequired ) + { + if ( Arr0 > pRequired[2 * pTuple->Obj0 + pTuple->Phase0] + 0.001 || Arr1 > pRequired[2 * pTuple->Obj1 + pTuple->Phase1] + 0.001 ) + { + if ( getenv("ABC_EMAP_DEBUG_MOG") && pTuples->nAreaSamples < 8 ) + { + printf( "ABC emap MOG req sample %d: roots=(%d,%d) phases=(%d,%d) arr=(%.2f,%.2f) req=(%.2f,%.2f) invreq=(%.2f,%.2f)\n", + pTuples->nAreaSamples, pTuple->Obj0, pTuple->Obj1, pTuple->Phase0, pTuple->Phase1, Arr0, Arr1, + pRequired[2 * pTuple->Obj0 + pTuple->Phase0], pRequired[2 * pTuple->Obj1 + pTuple->Phase1], + pRequired[2 * pTuple->Obj0 + !pTuple->Phase0], pRequired[2 * pTuple->Obj1 + !pTuple->Phase1] ); + pTuples->nAreaSamples++; + } + pTuples->nAreaRejectRequired++; + continue; + } + if ( (pRefs == NULL || pRefs[2 * pTuple->Obj0 + !pTuple->Phase0] > 0) && Arr0 + pLib->InvDelay > pRequired[2 * pTuple->Obj0 + !pTuple->Phase0] + 0.001 ) + { + if ( getenv("ABC_EMAP_DEBUG_MOG") && pTuples->nAreaSamples < 8 ) + { + printf( "ABC emap MOG invreq sample %d: roots=(%d,%d) phases=(%d,%d) arr=(%.2f,%.2f) req=(%.2f,%.2f) invreq=(%.2f,%.2f)\n", + pTuples->nAreaSamples, pTuple->Obj0, pTuple->Obj1, pTuple->Phase0, pTuple->Phase1, Arr0, Arr1, + pRequired[2 * pTuple->Obj0 + pTuple->Phase0], pRequired[2 * pTuple->Obj1 + pTuple->Phase1], + pRequired[2 * pTuple->Obj0 + !pTuple->Phase0], pRequired[2 * pTuple->Obj1 + !pTuple->Phase1] ); + pTuples->nAreaSamples++; + } + pTuples->nAreaRejectRequired++; + continue; + } + if ( (pRefs == NULL || pRefs[2 * pTuple->Obj1 + !pTuple->Phase1] > 0) && Arr1 + pLib->InvDelay > pRequired[2 * pTuple->Obj1 + !pTuple->Phase1] + 0.001 ) + { + pTuples->nAreaRejectRequired++; + continue; + } + } + if ( pRequired != NULL ) + { + if ( pBest0->Arr > pRequired[2 * pTuple->Obj0 + pTuple->Phase0] + 0.001 || pBest1->Arr > pRequired[2 * pTuple->Obj1 + pTuple->Phase1] + 0.001 ) + fRespectsRequired = 0; + if ( (pRefs == NULL || pRefs[2 * pTuple->Obj0 + !pTuple->Phase0] > 0) && pBest0->Arr + pLib->InvDelay > pRequired[2 * pTuple->Obj0 + !pTuple->Phase0] + 0.001 ) + fRespectsRequired = 0; + if ( (pRefs == NULL || pRefs[2 * pTuple->Obj1 + !pTuple->Phase1] > 0) && pBest1->Arr + pLib->InvDelay > pRequired[2 * pTuple->Obj1 + !pTuple->Phase1] + 0.001 ) + fRespectsRequired = 0; + } + { + float Est0 = (float)Abc_MaxInt( 1, pRefs ? pRefs[2 * pTuple->Obj0 + pTuple->Phase0] : Abc_ObjFanoutNum(Abc_NtkObj(pNtk, pTuple->Obj0)) ); + float Est1 = (float)Abc_MaxInt( 1, pRefs ? pRefs[2 * pTuple->Obj1 + pTuple->Phase1] : Abc_ObjFanoutNum(Abc_NtkObj(pNtk, pTuple->Obj1)) ); + OldFlow = pBest0->Flow / Est0 + pBest1->Flow / Est1; + CombinedRefs = Est0 + Est1; + } + for ( i = 0; i < pMog->nPins; i++ ) + { + int Leaf = pCut0->Leaves[pMog->PinToLeaf[i]]; + int LeafPhase = pMog->PinPhase[i]; + float Div = (float)Abc_MaxInt( 1, pRefs ? pRefs[2 * Leaf + LeafPhase] : Abc_ObjFanoutNum(Abc_NtkObj(pNtk, Leaf)) ); + LeafFlow += pMaps[Leaf].Best[LeafPhase].Flow / Div; + } + NewFlow = (pMog->Area + 2 * LeafFlow) / Abc_MaxFloat( 1.0f, CombinedRefs ); + NewScore = NewFlow; + if ( pRefs != NULL ) + { + if ( pRefs[2 * pTuple->Obj0 + !pTuple->Phase0] > 0 ) + NewScore += pLib->InvArea / Abc_MaxFloat( 1.0f, CombinedRefs ); + if ( pRefs[2 * pTuple->Obj1 + !pTuple->Phase1] > 0 ) + NewScore += pLib->InvArea / Abc_MaxFloat( 1.0f, CombinedRefs ); + } + if ( fRespectsRequired && NewFlow > OldFlow - 0.001 ) + { + pTuples->nAreaRejectFlow++; + continue; + } + if ( NewScore < BestScore - 0.001 || (NewScore < BestScore + 0.001 && NewFlow < BestFlow - 0.001) ) + { + iBestTuple = iTuple; + BestFlow = NewFlow; + BestScore = NewScore; + } + } + if ( iBestTuple < 0 ) + return 0; + { + Emap_Tuple_t * pTuple = &pTuples->pArray[iBestTuple]; + Emap_Mog_t * pMog = &pLib->pMogs[pTuple->Mog]; + Emap_PackEntry_t Entry0, Entry1; + memset( &Entry0, 0, sizeof(Entry0) ); + memset( &Entry1, 0, sizeof(Entry1) ); + Entry0.ObjId = pTuple->Obj0; + Entry0.Phase = pTuple->Phase0; + Entry0.Cut = pTuple->Cut0; + Entry1.ObjId = pTuple->Obj1; + Entry1.Phase = pTuple->Phase1; + Entry1.Cut = pTuple->Cut1; + Emap_MogApply( pMaps, &Entry0, &Entry1, pMog, pTuple->fSwap ); + pMaps[pTuple->Obj0].Best[pTuple->Phase0].Flow = BestFlow; + pMaps[pTuple->Obj1].Best[pTuple->Phase1].Flow = BestFlow; + Emap_MogSetOppositePhase( pMaps, pLib, pTuple->Obj0, pTuple->Phase0, BestFlow ); + Emap_MogSetOppositePhase( pMaps, pLib, pTuple->Obj1, pTuple->Phase1, BestFlow ); + pTuples->nAreaAccepts++; + return 1; + } +} + +static int Emap_ManPackMogs( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, double * pRequired, int * pRefs ) +{ + Emap_PackEntry_t * pEntries; + Abc_Obj_t * pObj; + int i, k, f, nEntries = 0, nPacked = 0; + if ( pLib->nMogs == 0 ) + return 0; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + pEntries = ABC_ALLOC( Emap_PackEntry_t, 2 * EMAP_CUT_MAX * Abc_NtkObjNumMax(pNtk) ); + Abc_AigForEachAnd( pNtk, pObj, i ) + { + for ( f = 0; f < 2; f++ ) + { + Emap_Best_t * pBest = &pMaps[Abc_ObjId(pObj)].Best[f]; + Emap_Obj_t * pMap = &pMaps[Abc_ObjId(pObj)]; + int c; + if ( pRefs[2 * Abc_ObjId(pObj) + f] == 0 || pBest->TwinObj >= 0 ) + continue; + for ( c = 0; c < pMap->nCuts; c++ ) + { + Emap_Cut_t * pCut = &pMap->Cuts[c]; + word Truth = f ? (pCut->Truth ^ Emap_TruthMask(pCut->nLeaves)) : pCut->Truth; + if ( pCut->nLeaves < 2 ) + continue; + pEntries[nEntries].ObjId = Abc_ObjId(pObj); + pEntries[nEntries].Phase = f; + pEntries[nEntries].Cut = c; + pEntries[nEntries].nLeaves = pCut->nLeaves; + pEntries[nEntries].Truth = Truth; + for ( k = 0; k < pCut->nLeaves; k++ ) + pEntries[nEntries].Leaves[k] = pCut->Leaves[k]; + nEntries++; + } + } + } + qsort( pEntries, nEntries, sizeof(Emap_PackEntry_t), Emap_PackEntryCompare ); + for ( i = 0; i < nEntries; i++ ) + { + Emap_PackEntry_t * pEntry0 = &pEntries[i]; + Emap_Best_t * pBest0 = &pMaps[pEntry0->ObjId].Best[pEntry0->Phase]; + Emap_Cut_t * pCut0; + if ( pBest0->TwinObj >= 0 ) + continue; + pCut0 = &pMaps[pEntry0->ObjId].Cuts[pEntry0->Cut]; + for ( k = 0; k < pLib->nMogs; k++ ) + { + Emap_Mog_t * pMog = &pLib->pMogs[k]; + int s; + if ( pMog->nPins != pCut0->nLeaves ) + continue; + for ( s = 0; s < 2; s++ ) + { + word Truth0 = s ? pMog->Truth1 : pMog->Truth0; + word Truth1 = s ? pMog->Truth0 : pMog->Truth1; + int Beg; + if ( Truth0 != pEntry0->Truth ) + continue; + if ( Emap_MogArrival( pMaps, pCut0, pMog, s ) > pRequired[2 * pEntry0->ObjId + pEntry0->Phase] + 0.001 ) + continue; + Beg = Emap_PackEntryFindFirst( pEntries, nEntries, pCut0, Truth1 ); + if ( Beg < 0 ) + continue; + for ( ; Beg < nEntries && pEntries[Beg].nLeaves == pCut0->nLeaves && pEntries[Beg].Truth == Truth1; Beg++ ) + { + Emap_PackEntry_t * pEntry1 = &pEntries[Beg]; + Emap_Best_t * pBest1 = &pMaps[pEntry1->ObjId].Best[pEntry1->Phase]; + Emap_Cut_t * pCut1 = &pMaps[pEntry1->ObjId].Cuts[pEntry1->Cut]; + int m, fSameLeaves = 1; + for ( m = 0; m < pCut0->nLeaves; m++ ) + if ( pEntry1->Leaves[m] != pCut0->Leaves[m] ) + fSameLeaves = 0; + if ( !fSameLeaves ) + break; + if ( pEntry1->ObjId == pEntry0->ObjId || pBest1->TwinObj >= 0 ) + continue; + if ( Emap_ObjPairHasDirectDanglingRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId ) ) + continue; + if ( Emap_MogArrival( pMaps, pCut1, pMog, !s ) > pRequired[2 * pEntry1->ObjId + pEntry1->Phase] + 0.001 ) + continue; + Emap_MogApply( pMaps, pEntry0, pEntry1, pMog, s ); + nPacked++; + break; + } + if ( pBest0->TwinObj >= 0 ) + break; + } + if ( pBest0->TwinObj >= 0 ) + break; + } + } + ABC_FREE( pEntries ); + return nPacked; +} + +static int Emap_ManRecoverMogsExact( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, double * pRequired, int * pRefs ) +{ + Emap_PackEntry_t * pEntries; + Vec_Int_t * vTouched; + Abc_Obj_t * pObj; + int i, k, f, nEntries = 0, nApplied = 0; + if ( pLib->nMogs == 0 ) + return 0; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + pEntries = ABC_ALLOC( Emap_PackEntry_t, 2 * EMAP_CUT_MAX * Abc_NtkObjNumMax(pNtk) ); + vTouched = Vec_IntAlloc( 1000 ); + Abc_AigForEachAnd( pNtk, pObj, i ) + { + for ( f = 0; f < 2; f++ ) + { + Emap_Obj_t * pMap = &pMaps[Abc_ObjId(pObj)]; + int c; + if ( pRefs[2 * Abc_ObjId(pObj) + f] == 0 || pMap->Best[f].TwinObj >= 0 ) + continue; + for ( c = 0; c < pMap->nCuts; c++ ) + { + Emap_Cut_t * pCut = &pMap->Cuts[c]; + word Truth = f ? (pCut->Truth ^ Emap_TruthMask(pCut->nLeaves)) : pCut->Truth; + if ( pCut->nLeaves < 2 ) + continue; + pEntries[nEntries].ObjId = Abc_ObjId(pObj); + pEntries[nEntries].Phase = f; + pEntries[nEntries].Cut = c; + pEntries[nEntries].nLeaves = pCut->nLeaves; + pEntries[nEntries].Truth = Truth; + for ( k = 0; k < pCut->nLeaves; k++ ) + pEntries[nEntries].Leaves[k] = pCut->Leaves[k]; + nEntries++; + } + } + } + qsort( pEntries, nEntries, sizeof(Emap_PackEntry_t), Emap_PackEntryCompare ); + for ( i = 0; i < nEntries; i++ ) + { + Emap_PackEntry_t * pEntry0 = &pEntries[i]; + Emap_Best_t * pBest0 = &pMaps[pEntry0->ObjId].Best[pEntry0->Phase]; + Emap_Cut_t * pCut0; + if ( pRefs[2 * pEntry0->ObjId + pEntry0->Phase] == 0 || pBest0->TwinObj >= 0 ) + continue; + pCut0 = &pMaps[pEntry0->ObjId].Cuts[pEntry0->Cut]; + for ( k = 0; k < pLib->nMogs; k++ ) + { + Emap_Mog_t * pMog = &pLib->pMogs[k]; + int s; + if ( pMog->nPins != pCut0->nLeaves ) + continue; + for ( s = 0; s < 2; s++ ) + { + word Truth0 = s ? pMog->Truth1 : pMog->Truth0; + word Truth1 = s ? pMog->Truth0 : pMog->Truth1; + int Beg; + if ( Truth0 != pEntry0->Truth ) + continue; + if ( Emap_MogArrival( pMaps, pCut0, pMog, s ) > pRequired[2 * pEntry0->ObjId + pEntry0->Phase] + 0.001 ) + continue; + Beg = Emap_PackEntryFindFirst( pEntries, nEntries, pCut0, Truth1 ); + if ( Beg < 0 ) + continue; + for ( ; Beg < nEntries && pEntries[Beg].nLeaves == pCut0->nLeaves && pEntries[Beg].Truth == Truth1; Beg++ ) + { + Emap_PackEntry_t * pEntry1 = &pEntries[Beg]; + Emap_Best_t * pBest1 = &pMaps[pEntry1->ObjId].Best[pEntry1->Phase]; + Emap_Best_t OldBest0, OldBest1; + float AreaOld, AreaNew; + int m, Entry, t, fSameLeaves = 1; + for ( m = 0; m < pCut0->nLeaves; m++ ) + if ( pEntry1->Leaves[m] != pCut0->Leaves[m] ) + fSameLeaves = 0; + if ( !fSameLeaves ) + break; + if ( pEntry1->ObjId == pEntry0->ObjId || pRefs[2 * pEntry1->ObjId + pEntry1->Phase] == 0 || pBest1->TwinObj >= 0 ) + continue; + if ( Emap_ObjPairHasDirectDanglingRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId ) ) + continue; + if ( Emap_ObjPairHasTfiRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId ) ) + continue; + if ( Emap_MogArrival( pMaps, &pMaps[pEntry1->ObjId].Cuts[pEntry1->Cut], pMog, !s ) > pRequired[2 * pEntry1->ObjId + pEntry1->Phase] + 0.001 ) + continue; + + OldBest0 = *pBest0; + OldBest1 = *pBest1; + AreaOld = Emap_CutDerefLeaves_rec( pNtk, pMaps, pLib, pRefs, pEntry0->ObjId, pEntry0->Phase ); + AreaOld += Emap_CutDerefLeaves_rec( pNtk, pMaps, pLib, pRefs, pEntry1->ObjId, pEntry1->Phase ); + Emap_MogApply( pMaps, pEntry0, pEntry1, pMog, s ); + AreaNew = pMog->Area; + Vec_IntClear( vTouched ); + AreaNew += Emap_CutRefOnlyLeavesVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, pEntry0->ObjId, pEntry0->Phase ); + AreaNew += Emap_CutRefOnlyLeavesVisit_rec( pNtk, pMaps, pLib, pRefs, vTouched, pEntry1->ObjId, pEntry1->Phase ); + Vec_IntForEachEntryReverse( vTouched, Entry, t ) + pRefs[Entry]--; + if ( AreaNew < AreaOld - 0.001 ) + { + Emap_CutRefOnlyLeaves_rec( pNtk, pMaps, pLib, pRefs, pEntry0->ObjId, pEntry0->Phase ); + Emap_CutRefOnlyLeaves_rec( pNtk, pMaps, pLib, pRefs, pEntry1->ObjId, pEntry1->Phase ); + nApplied++; + break; + } + *pBest0 = OldBest0; + *pBest1 = OldBest1; + Emap_CutRefLeaves_rec( pNtk, pMaps, pLib, pRefs, pEntry0->ObjId, pEntry0->Phase ); + Emap_CutRefLeaves_rec( pNtk, pMaps, pLib, pRefs, pEntry1->ObjId, pEntry1->Phase ); + } + if ( pBest0->TwinObj >= 0 ) + break; + } + if ( pBest0->TwinObj >= 0 ) + break; + } + } + Vec_IntFree( vTouched ); + ABC_FREE( pEntries ); + return nApplied; +} + +static int Emap_ManRecoverMogsExactMffc( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Mio_Library_t * pMio, double * pRequired, int * pRefs, double DelayLimit, float * pAreaBest, double * pDelayBest ) +{ + Emap_PackEntry_t * pEntries; + Vec_Int_t * vMffcTouched; + int * pDecs; + char * pLeafMarks; + Abc_Obj_t * pObj; + float AreaBest = *pAreaBest; + double DelayBest = *pDelayBest; + int i, k, f, nEntries = 0, nApplied = 0, nTried = 0; + if ( pLib->nMogs == 0 ) + return 0; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + pEntries = ABC_ALLOC( Emap_PackEntry_t, 2 * EMAP_CUT_MAX * Abc_NtkObjNumMax(pNtk) ); + vMffcTouched = Vec_IntAlloc( 100 ); + pDecs = ABC_CALLOC( int, Abc_NtkObjNumMax(pNtk) ); + pLeafMarks = ABC_CALLOC( char, Abc_NtkObjNumMax(pNtk) ); + Abc_AigForEachAnd( pNtk, pObj, i ) + { + for ( f = 0; f < 2; f++ ) + { + Emap_Obj_t * pMap = &pMaps[Abc_ObjId(pObj)]; + int c; + if ( pRefs[2 * Abc_ObjId(pObj)] + pRefs[2 * Abc_ObjId(pObj) + 1] == 0 || pMap->Best[0].TwinObj >= 0 || pMap->Best[1].TwinObj >= 0 ) + continue; + for ( c = 0; c < pMap->nCuts; c++ ) + { + Emap_Cut_t * pCut = &pMap->Cuts[c]; + word Truth = f ? (pCut->Truth ^ Emap_TruthMask(pCut->nLeaves)) : pCut->Truth; + if ( pCut->nLeaves < 2 || pCut->nLeaves > 3 ) + continue; + pEntries[nEntries].ObjId = Abc_ObjId(pObj); + pEntries[nEntries].Phase = f; + pEntries[nEntries].Cut = c; + pEntries[nEntries].nLeaves = pCut->nLeaves; + pEntries[nEntries].Truth = Truth; + for ( k = 0; k < pCut->nLeaves; k++ ) + pEntries[nEntries].Leaves[k] = pCut->Leaves[k]; + nEntries++; + } + } + } + qsort( pEntries, nEntries, sizeof(Emap_PackEntry_t), Emap_PackEntryCompare ); + for ( i = 0; i < nEntries; i++ ) + { + Emap_PackEntry_t * pEntry0 = &pEntries[i]; + Emap_Obj_t * pMap0 = &pMaps[pEntry0->ObjId]; + Emap_Cut_t * pCut0; + if ( pRefs[2 * pEntry0->ObjId] + pRefs[2 * pEntry0->ObjId + 1] == 0 || pMap0->Best[0].TwinObj >= 0 || pMap0->Best[1].TwinObj >= 0 ) + continue; + pCut0 = &pMaps[pEntry0->ObjId].Cuts[pEntry0->Cut]; + for ( k = 0; k < pLib->nMogs; k++ ) + { + Emap_Mog_t * pMog = &pLib->pMogs[k]; + int s; + if ( pMog->nPins != pCut0->nLeaves ) + continue; + for ( s = 0; s < 2; s++ ) + { + word Truth0 = s ? pMog->Truth1 : pMog->Truth0; + word Truth1 = s ? pMog->Truth0 : pMog->Truth1; + int Beg; + if ( Truth0 != pEntry0->Truth ) + continue; + if ( Emap_MogArrival( pMaps, pCut0, pMog, s ) > pRequired[2 * pEntry0->ObjId + pEntry0->Phase] + 0.001 ) + continue; + Beg = Emap_PackEntryFindFirst( pEntries, nEntries, pCut0, Truth1 ); + if ( Beg < 0 ) + continue; + for ( ; Beg < nEntries && pEntries[Beg].nLeaves == pCut0->nLeaves && pEntries[Beg].Truth == Truth1; Beg++ ) + { + Emap_PackEntry_t * pEntry1 = &pEntries[Beg]; + Emap_Obj_t * pMap1 = &pMaps[pEntry1->ObjId]; + Emap_Best_t OldBest00, OldBest01, OldBest10, OldBest11; + float AreaCur; + double DelayCur; + int m, fSameLeaves = 1; + for ( m = 0; m < pCut0->nLeaves; m++ ) + if ( pEntry1->Leaves[m] != pCut0->Leaves[m] ) + fSameLeaves = 0; + if ( !fSameLeaves ) + break; + if ( pEntry1->ObjId == pEntry0->ObjId || pRefs[2 * pEntry1->ObjId] + pRefs[2 * pEntry1->ObjId + 1] == 0 || pMap1->Best[0].TwinObj >= 0 || pMap1->Best[1].TwinObj >= 0 ) + continue; + if ( Emap_ObjPairHasMffcDanglingRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId, pCut0, pLeafMarks, pDecs, vMffcTouched ) ) + continue; + if ( Emap_MogArrival( pMaps, &pMaps[pEntry1->ObjId].Cuts[pEntry1->Cut], pMog, !s ) > pRequired[2 * pEntry1->ObjId + pEntry1->Phase] + 0.001 ) + continue; + OldBest00 = pMap0->Best[0]; + OldBest01 = pMap0->Best[1]; + OldBest10 = pMap1->Best[0]; + OldBest11 = pMap1->Best[1]; + Emap_MogApply( pMaps, pEntry0, pEntry1, pMog, s ); + Emap_MogSetOppositePhase( pMaps, pLib, pEntry0->ObjId, pEntry0->Phase, pMog->Area ); + Emap_MogSetOppositePhase( pMaps, pLib, pEntry1->ObjId, pEntry1->Phase, pMog->Area ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, pLib, pMio, &DelayCur ); + nTried++; + if ( DelayCur <= DelayLimit + EMAP_DELAY_EPS && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nApplied++; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + break; + } + pMap0->Best[0] = OldBest00; + pMap0->Best[1] = OldBest01; + pMap1->Best[0] = OldBest10; + pMap1->Best[1] = OldBest11; + } + if ( pMap0->Best[0].TwinObj >= 0 || pMap0->Best[1].TwinObj >= 0 ) + break; + } + if ( pMap0->Best[0].TwinObj >= 0 || pMap0->Best[1].TwinObj >= 0 ) + break; + } + } + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG MFFC-exact trial: entries=%d tried=%d applied=%d area=%.2f delay=%.2f\n", nEntries, nTried, nApplied, AreaBest, DelayBest ); + *pAreaBest = AreaBest; + *pDelayBest = DelayBest; + ABC_FREE( pLeafMarks ); + ABC_FREE( pDecs ); + Vec_IntFree( vMffcTouched ); + ABC_FREE( pEntries ); + return nApplied; +} + +static int Emap_ManRecoverMogsTimed( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Mio_Library_t * pMio, int * pRefs, double DelayTarget, float * pAreaBest ) +{ + Emap_PackEntry_t * pEntries; + Abc_Obj_t * pObj; + float AreaBest = *pAreaBest; + double DelayCur; + int i, k, f, nEntries = 0, nApplied = 0; + if ( pLib->nMogs == 0 ) + return 0; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + pEntries = ABC_ALLOC( Emap_PackEntry_t, 2 * EMAP_CUT_MAX * Abc_NtkObjNumMax(pNtk) ); + Abc_AigForEachAnd( pNtk, pObj, i ) + { + for ( f = 0; f < 2; f++ ) + { + Emap_Obj_t * pMap = &pMaps[Abc_ObjId(pObj)]; + int c; + if ( pRefs[2 * Abc_ObjId(pObj) + f] == 0 ) + continue; + for ( c = 0; c < pMap->nCuts; c++ ) + { + Emap_Cut_t * pCut = &pMap->Cuts[c]; + word Truth = f ? (pCut->Truth ^ Emap_TruthMask(pCut->nLeaves)) : pCut->Truth; + if ( pCut->nLeaves < 2 ) + continue; + pEntries[nEntries].ObjId = Abc_ObjId(pObj); + pEntries[nEntries].Phase = f; + pEntries[nEntries].Cut = c; + pEntries[nEntries].nLeaves = pCut->nLeaves; + pEntries[nEntries].Truth = Truth; + for ( k = 0; k < pCut->nLeaves; k++ ) + pEntries[nEntries].Leaves[k] = pCut->Leaves[k]; + nEntries++; + } + } + } + qsort( pEntries, nEntries, sizeof(Emap_PackEntry_t), Emap_PackEntryCompare ); + for ( i = 0; i < nEntries; i++ ) + { + Emap_PackEntry_t * pEntry0 = &pEntries[i]; + Emap_Best_t * pBest0 = &pMaps[pEntry0->ObjId].Best[pEntry0->Phase]; + Emap_Cut_t * pCut0; + if ( pRefs[2 * pEntry0->ObjId + pEntry0->Phase] == 0 || pBest0->TwinObj >= 0 ) + continue; + pCut0 = &pMaps[pEntry0->ObjId].Cuts[pEntry0->Cut]; + for ( k = 0; k < pLib->nMogs; k++ ) + { + Emap_Mog_t * pMog = &pLib->pMogs[k]; + int s; + if ( pMog->nPins != pCut0->nLeaves ) + continue; + for ( s = 0; s < 2; s++ ) + { + word Truth0 = s ? pMog->Truth1 : pMog->Truth0; + word Truth1 = s ? pMog->Truth0 : pMog->Truth1; + int Beg; + if ( Truth0 != pEntry0->Truth ) + continue; + Beg = Emap_PackEntryFindFirst( pEntries, nEntries, pCut0, Truth1 ); + if ( Beg < 0 ) + continue; + for ( ; Beg < nEntries && pEntries[Beg].nLeaves == pCut0->nLeaves && pEntries[Beg].Truth == Truth1; Beg++ ) + { + Emap_PackEntry_t * pEntry1 = &pEntries[Beg]; + Emap_Best_t * pBest1 = &pMaps[pEntry1->ObjId].Best[pEntry1->Phase]; + Emap_Best_t OldBest0, OldBest1; + float AreaCur; + int m, fSameLeaves = 1; + for ( m = 0; m < pCut0->nLeaves; m++ ) + if ( pEntry1->Leaves[m] != pCut0->Leaves[m] ) + fSameLeaves = 0; + if ( !fSameLeaves ) + break; + if ( pEntry1->ObjId == pEntry0->ObjId || pRefs[2 * pEntry1->ObjId + pEntry1->Phase] == 0 || pBest1->TwinObj >= 0 ) + continue; + if ( Emap_ObjPairHasDirectDanglingRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId ) ) + continue; + if ( Emap_ObjPairHasTfiRelation( pNtk, pEntry0->ObjId, pEntry1->ObjId ) ) + continue; + OldBest0 = *pBest0; + OldBest1 = *pBest1; + Emap_MogApply( pMaps, pEntry0, pEntry1, pMog, s ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, pLib, pMio, &DelayCur ); + if ( DelayCur <= DelayTarget + EMAP_DELAY_EPS && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + nApplied++; + Emap_ManComputeRefs( pNtk, pMaps, pLib, pRefs ); + break; + } + *pBest0 = OldBest0; + *pBest1 = OldBest1; + } + if ( pBest0->TwinObj >= 0 ) + break; + } + if ( pBest0->TwinObj >= 0 ) + break; + } + } + *pAreaBest = AreaBest; + ABC_FREE( pEntries ); + return nApplied; +} + +static Abc_Ntk_t * Emap_ManBuildMappedNtk( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Mio_Library_t * pMio ) +{ + Abc_Ntk_t * pNtkNew; + Abc_Obj_t * pObj, * pObjNew, * pFanin; + Vec_Int_t * vCopy; + int i; + pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_MAP, 1 ); + pNtkNew->pName = Extra_UtilStrsav( pNtk->pName ? pNtk->pName : "emap" ); + pNtkNew->pManFunc = pMio; + vCopy = Vec_IntStartFull( 2 * Abc_NtkObjNumMax(pNtk) ); + Abc_NtkForEachPi( pNtk, pObj, i ) + { + pObjNew = Abc_NtkCreatePi( pNtkNew ); + Abc_ObjAssignName( pObjNew, Abc_ObjName(pObj), NULL ); + Vec_IntWriteEntry( vCopy, 2 * Abc_ObjId(pObj) + 0, Abc_ObjId(pObjNew) ); + } + Abc_NtkForEachPo( pNtk, pObj, i ) + { + pObjNew = Abc_NtkCreatePo( pNtkNew ); + Abc_ObjAssignName( pObjNew, Abc_ObjName(pObj), NULL ); + pFanin = Emap_ManBuildPhase_rec( pNtk, pNtkNew, pMaps, vCopy, Abc_ObjFaninId0(pObj), Abc_ObjFaninC0(pObj), pLib ); + if ( pFanin == NULL ) + { + Vec_IntFree( vCopy ); + Abc_NtkDelete( pNtkNew ); + return NULL; + } + Abc_ObjAddFanin( pObjNew, pFanin ); + } + Vec_IntFree( vCopy ); + if ( !Abc_NtkCheck( pNtkNew ) ) + { + Abc_NtkDelete( pNtkNew ); + return NULL; + } + return pNtkNew; +} + +static float Emap_ManComputeActualMappedStats( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Mio_Library_t * pMio, double * pDelay ) +{ + Abc_Ntk_t * pNtkNew = Emap_ManBuildMappedNtk( pNtk, pMaps, pLib, pMio ); + float Area; + if ( pNtkNew == NULL ) + { + *pDelay = EMAP_DOUBLE_LARGE; + return EMAP_FLOAT_LARGE; + } + *pDelay = Abc_NtkDelayTrace( pNtkNew, NULL, NULL, 0 ); + Area = (float)Abc_NtkGetMappedArea( pNtkNew ); + Abc_NtkDelete( pNtkNew ); + return Area; +} + +static int Emap_ManTryExactRecoveries( Abc_Ntk_t * pNtk, Emap_Obj_t * pMaps, Emap_Lib_t * pLib, Mio_Library_t * pMio, Emap_Tuples_t * pTuples, double * pRequired, int * pRefs, Emap_Best_t * pBase, Emap_Best_t * pSave, float * pAreaBest, double * pDelayBest, double DelayTarget ) +{ + float AreaCur, AreaBase, AreaBest = EMAP_FLOAT_LARGE; + double DelayCur, DelayBase, DelayBest = EMAP_DOUBLE_LARGE; + int Mode, fHaveBest = 0, nChanges, nChangesBest = 0; + for ( Mode = 0; Mode < 4; Mode++ ) + { + int fRelax = Mode & 1; + int fDropPhase = (Mode >> 1) & 1; + Emap_ManRestoreBests( pNtk, pMaps, pBase ); + nChanges = Emap_ManRecoverExactArea( pNtk, pMaps, pLib, pTuples, pRequired, pRefs, 2, DelayTarget, fRelax, fDropPhase ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, pLib, pMio, &DelayCur ); + if ( DelayCur <= DelayTarget + EMAP_DELAY_EPS && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nChangesBest = nChanges; + Emap_ManSaveBests( pNtk, pMaps, pSave ); + fHaveBest = 1; + } + } + if ( fHaveBest ) + { + Emap_ManRestoreBests( pNtk, pMaps, pSave ); + *pAreaBest = AreaBest; + *pDelayBest = DelayBest; + return nChangesBest; + } + Emap_ManRestoreBests( pNtk, pMaps, pBase ); + AreaBase = Emap_ManComputeActualMappedStats( pNtk, pMaps, pLib, pMio, &DelayBase ); + Emap_ManSaveBests( pNtk, pMaps, pSave ); + *pAreaBest = AreaBase; + *pDelayBest = DelayBase; + return 0; +} + +/**Function************************************************************* + + Synopsis [Creates a mapped network by cut matching AIG nodes.] + +***********************************************************************/ +Abc_Ntk_t * Emap_ManMapAigStructural( Abc_Ntk_t * pNtk, Mio_Library_t * pMio, int fUseMogs, int fAreaMode, int fVerbose ) +{ + Emap_Lib_t Lib; + Emap_Tuples_t Tuples; + Emap_Obj_t * pMaps; + Abc_Ntk_t * pNtkNew; + Abc_Obj_t * pObj; + double * pRequired = NULL, DelayTarget = 0, DelayLimit = 0; + Emap_Best_t * pBestSave = NULL; + Emap_Best_t * pBestRound = NULL; + Emap_Best_t * pBestTrial = NULL; + float AreaBest, AreaCur; + double DelayBest, DelayCur; + int * pRefs = NULL; + int i, r, nNodesMapped = 0, nNodesFailed = 0, nMogsPacked = 0, nMogsBest = 0, nExactChanges = 0, nExactChangesBest = 0; + + assert( Abc_NtkIsStrash(pNtk) ); + memset( &Tuples, 0, sizeof(Tuples) ); + if ( !Emap_LibPrepare( &Lib, pMio ) ) + return NULL; + + pMaps = ABC_CALLOC( Emap_Obj_t, Abc_NtkObjNumMax(pNtk) ); + Emap_NodeAddConstCut( &pMaps[Abc_ObjId(Abc_AigConst1(pNtk))] ); + pMaps[Abc_ObjId(Abc_AigConst1(pNtk))].Best[0].Arr = 0; + pMaps[Abc_ObjId(Abc_AigConst1(pNtk))].Best[0].Flow = 0; + pMaps[Abc_ObjId(Abc_AigConst1(pNtk))].Best[1].Arr = Lib.InvDelay; + pMaps[Abc_ObjId(Abc_AigConst1(pNtk))].Best[1].Flow = Lib.InvArea; + pMaps[Abc_ObjId(Abc_AigConst1(pNtk))].Best[1].fInv = 1; + + Abc_NtkForEachPi( pNtk, pObj, i ) + { + Emap_NodeAddUnitCut( &pMaps[Abc_ObjId(pObj)], Abc_ObjId(pObj) ); + pMaps[Abc_ObjId(pObj)].Best[0].Arr = 0; + pMaps[Abc_ObjId(pObj)].Best[0].Flow = 0; + pMaps[Abc_ObjId(pObj)].Best[1].Arr = Lib.InvDelay; + pMaps[Abc_ObjId(pObj)].Best[1].Flow = Lib.InvArea; + pMaps[Abc_ObjId(pObj)].Best[1].fInv = 1; + } + + Abc_AigForEachAnd( pNtk, pObj, i ) + { + Emap_NodeMergeCuts( pMaps, pObj ); + Emap_NodeMatch( pMaps, &pMaps[Abc_ObjId(pObj)], &Lib, pObj, NULL, NULL ); + if ( pMaps[Abc_ObjId(pObj)].Best[0].pGate ) + nNodesMapped++; + else + nNodesFailed++; + } + if ( nNodesFailed ) + printf( "Warning: %d AIG nodes did not receive a direct cut match.\n", nNodesFailed ); + if ( fUseMogs ) + Emap_ManComputeMogTuples( pNtk, pMaps, &Lib, &Tuples ); + + pRequired = ABC_ALLOC( double, 2 * Abc_NtkObjNumMax(pNtk) ); + pRefs = ABC_ALLOC( int, 2 * Abc_NtkObjNumMax(pNtk) ); + pBestSave = ABC_ALLOC( Emap_Best_t, 2 * Abc_NtkObjNumMax(pNtk) ); + pBestRound = ABC_ALLOC( Emap_Best_t, 2 * Abc_NtkObjNumMax(pNtk) ); + pBestTrial = ABC_ALLOC( Emap_Best_t, 2 * Abc_NtkObjNumMax(pNtk) ); + DelayTarget = Emap_ManComputeRequired( pNtk, pMaps, &Lib, pRequired ); + DelayLimit = fAreaMode ? EMAP_DOUBLE_LARGE / 4 : DelayTarget; + if ( fAreaMode ) + for ( i = 0; i < 2 * Abc_NtkObjNumMax(pNtk); i++ ) + pRequired[i] = EMAP_DOUBLE_LARGE; + Emap_ManSaveBests( pNtk, pMaps, pBestTrial ); + nExactChangesBest = Emap_ManTryExactRecoveries( pNtk, pMaps, &Lib, pMio, fUseMogs ? &Tuples : NULL, pRequired, pRefs, pBestTrial, pBestRound, &AreaBest, &DelayBest, DelayLimit ); + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + Emap_ManSaveBests( pNtk, pMaps, pBestRound ); + if ( fUseMogs ) + { + int fAcceptedThisRound = 0; + if ( getenv("ABC_EMAP_TIMED_MOG") ) + { + float AreaTimed = AreaBest; + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + nMogsPacked = Emap_ManRecoverMogsTimed( pNtk, pMaps, &Lib, pMio, pRefs, DelayLimit, &AreaTimed ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG timed trial initial: applied=%d area=%.2f best=%.2f\n", nMogsPacked, AreaTimed, AreaBest ); + if ( nMogsPacked && AreaTimed < AreaBest - 0.001 ) + { + AreaBest = AreaTimed; + nMogsBest = nMogsPacked; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + } + nMogsPacked = Emap_ManRecoverMogsExact( pNtk, pMaps, &Lib, pRequired, pRefs ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, &Lib, pMio, &DelayCur ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG exact trial initial: applied=%d area=%.2f delay=%.2f best=%.2f\n", nMogsPacked, AreaCur, DelayCur, AreaBest ); + if ( nMogsPacked && (fAreaMode || DelayCur <= DelayTarget + EMAP_DELAY_EPS) && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nMogsBest = nMogsPacked; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + if ( getenv("ABC_EMAP_MFFC_EXACT") ) + { + float AreaMffc = AreaBest; + double DelayMffc = DelayBest; + nMogsPacked = Emap_ManRecoverMogsExactMffc( pNtk, pMaps, &Lib, pMio, pRequired, pRefs, DelayLimit, &AreaMffc, &DelayMffc ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG MFFC exact trial initial: applied=%d area=%.2f delay=%.2f best=%.2f\n", nMogsPacked, AreaMffc, DelayMffc, AreaBest ); + if ( nMogsPacked && AreaMffc < AreaBest - 0.001 ) + { + AreaBest = AreaMffc; + DelayBest = DelayMffc; + nMogsBest = nMogsPacked; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + } + nMogsPacked = Emap_ManPackMogs( pNtk, pMaps, &Lib, pRequired, pRefs ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, &Lib, pMio, &DelayCur ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG pack trial initial: applied=%d area=%.2f delay=%.2f best=%.2f\n", nMogsPacked, AreaCur, DelayCur, AreaBest ); + if ( nMogsPacked && (fAreaMode || DelayCur <= DelayTarget + EMAP_DELAY_EPS) && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nMogsBest = nMogsPacked; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, fAcceptedThisRound ? pBestSave : pBestRound ); + } + for ( r = 0; r < 6; r++ ) + { + int nMogsCur; + Emap_ManComputeRefs( pNtk, pMaps, &Lib, pRefs ); + if ( fAreaMode ) + for ( i = 0; i < 2 * Abc_NtkObjNumMax(pNtk); i++ ) + pRequired[i] = EMAP_DOUBLE_LARGE; + else + Emap_ManComputeRequiredTarget( pNtk, pMaps, &Lib, pRequired, pRefs, DelayTarget ); + nNodesMapped = nNodesFailed = 0; + Abc_AigForEachAnd( pNtk, pObj, i ) + { + Emap_NodeMatch( pMaps, &pMaps[Abc_ObjId(pObj)], &Lib, pObj, pRequired, pRefs ); + if ( fUseMogs && !getenv("ABC_EMAP_SKIP_MOG_AREA") ) + Emap_NodeMatchMogArea( pNtk, pMaps, &Lib, &Tuples, pRefs, pRequired, Abc_ObjId(pObj), 1 ); + if ( pMaps[Abc_ObjId(pObj)].Best[0].pGate ) + nNodesMapped++; + else + nNodesFailed++; + } + Emap_ManSaveBests( pNtk, pMaps, pBestTrial ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, &Lib, pMio, &DelayCur ); + if ( fUseMogs && (fAreaMode || DelayCur <= DelayTarget + EMAP_DELAY_EPS) && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nMogsBest = Tuples.nAreaAccepts; + nExactChangesBest = nExactChanges; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + Emap_ManSaveBests( pNtk, pMaps, pBestRound ); + } + nExactChanges = Emap_ManTryExactRecoveries( pNtk, pMaps, &Lib, pMio, fUseMogs ? &Tuples : NULL, pRequired, pRefs, pBestTrial, pBestRound, &AreaCur, &DelayCur, DelayLimit ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, &Lib, pMio, &DelayCur ); + if ( (fAreaMode || DelayCur <= DelayTarget + EMAP_DELAY_EPS) && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nMogsBest = 0; + nExactChangesBest = nExactChanges; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + Emap_ManSaveBests( pNtk, pMaps, pBestRound ); + } + if ( fUseMogs ) + { + int fAcceptedThisRound = 0; + if ( getenv("ABC_EMAP_TIMED_MOG") ) + { + float AreaTimed = AreaBest; + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + nMogsCur = Emap_ManRecoverMogsTimed( pNtk, pMaps, &Lib, pMio, pRefs, DelayLimit, &AreaTimed ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG timed trial round %d: applied=%d area=%.2f best=%.2f\n", r, nMogsCur, AreaTimed, AreaBest ); + if ( nMogsCur && AreaTimed < AreaBest - 0.001 ) + { + AreaBest = AreaTimed; + nMogsBest = nMogsCur; + nExactChangesBest = nExactChanges; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + } + nMogsCur = Emap_ManRecoverMogsExact( pNtk, pMaps, &Lib, pRequired, pRefs ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, &Lib, pMio, &DelayCur ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG exact trial round %d: applied=%d area=%.2f delay=%.2f best=%.2f\n", r, nMogsCur, AreaCur, DelayCur, AreaBest ); + if ( nMogsCur && (fAreaMode || DelayCur <= DelayTarget + EMAP_DELAY_EPS) && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nMogsBest = nMogsCur; + nExactChangesBest = nExactChanges; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + if ( getenv("ABC_EMAP_MFFC_EXACT") ) + { + float AreaMffc = AreaBest; + double DelayMffc = DelayBest; + nMogsCur = Emap_ManRecoverMogsExactMffc( pNtk, pMaps, &Lib, pMio, pRequired, pRefs, DelayLimit, &AreaMffc, &DelayMffc ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG MFFC exact trial round %d: applied=%d area=%.2f delay=%.2f best=%.2f\n", r, nMogsCur, AreaMffc, DelayMffc, AreaBest ); + if ( nMogsCur && AreaMffc < AreaBest - 0.001 ) + { + AreaBest = AreaMffc; + DelayBest = DelayMffc; + nMogsBest = nMogsCur; + nExactChangesBest = nExactChanges; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, pBestRound ); + } + nMogsCur = Emap_ManPackMogs( pNtk, pMaps, &Lib, pRequired, pRefs ); + AreaCur = Emap_ManComputeActualMappedStats( pNtk, pMaps, &Lib, pMio, &DelayCur ); + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + printf( "ABC emap MOG pack trial round %d: applied=%d area=%.2f delay=%.2f best=%.2f\n", r, nMogsCur, AreaCur, DelayCur, AreaBest ); + if ( nMogsCur && (fAreaMode || DelayCur <= DelayTarget + EMAP_DELAY_EPS) && AreaCur < AreaBest - 0.001 ) + { + AreaBest = AreaCur; + DelayBest = DelayCur; + nMogsBest = nMogsCur; + nExactChangesBest = nExactChanges; + Emap_ManSaveBests( pNtk, pMaps, pBestSave ); + fAcceptedThisRound = 1; + } + Emap_ManRestoreBests( pNtk, pMaps, fAcceptedThisRound ? pBestSave : pBestRound ); + } + } + Emap_ManRestoreBests( pNtk, pMaps, pBestSave ); + nMogsPacked = nMogsBest; + if ( nNodesFailed ) + printf( "Warning: %d AIG nodes did not receive an area-recovery match.\n", nNodesFailed ); + + pNtkNew = Emap_ManBuildMappedNtk( pNtk, pMaps, &Lib, pMio ); + if ( pNtkNew == NULL ) + { + Emap_LibFree( &Lib ); + Emap_TuplesFree( &Tuples ); + ABC_FREE( pMaps ); + ABC_FREE( pRequired ); + ABC_FREE( pRefs ); + ABC_FREE( pBestSave ); + ABC_FREE( pBestRound ); + ABC_FREE( pBestTrial ); + return NULL; + } + + if ( getenv("ABC_EMAP_DEBUG_MOG") ) + { + printf( "ABC emap MOG area: tuples=%d calls=%d candidates=%d accepts=%d reject_twin=%d reject_required=%d reject_flow=%d\n", + Tuples.nSize, Tuples.nAreaCalls, Tuples.nAreaCandidates, Tuples.nAreaAccepts, + Tuples.nAreaRejectTwin, Tuples.nAreaRejectRequired, Tuples.nAreaRejectFlow ); + printf( "ABC emap MOG local exact: calls=%d candidates=%d accepts=%d reject_unused=%d reject_twin=%d reject_shared=%d reject_required=%d reject_area=%d\n", + Tuples.nExactLocalCalls, Tuples.nExactLocalCandidates, Tuples.nExactLocalAccepts, + Tuples.nExactLocalRejectUnused, Tuples.nExactLocalRejectTwin, Tuples.nExactLocalRejectShared, + Tuples.nExactLocalRejectRequired, Tuples.nExactLocalRejectArea ); + printf( "ABC emap MOG local exact by arity: cand2=%d cand3=%d accept2=%d accept3=%d\n", + Tuples.nExactLocalCand2, Tuples.nExactLocalCand3, Tuples.nExactLocalAccept2, Tuples.nExactLocalAccept3 ); + } + + if ( fVerbose ) + printf( "ABC-native emap mapped %d AIG nodes using %d GENLIB truth variants, %d MOG variants, %d exact-cover changes, and packed %d MOG pairs in %s mode with delay target %.2f.\n", nNodesMapped, Lib.nCells, Lib.nMogs, nExactChangesBest, nMogsPacked, fAreaMode ? "area" : "delay", DelayTarget ); + + Emap_LibFree( &Lib ); + Emap_TuplesFree( &Tuples ); + ABC_FREE( pMaps ); + ABC_FREE( pRequired ); + ABC_FREE( pRefs ); + ABC_FREE( pBestSave ); + ABC_FREE( pBestRound ); + ABC_FREE( pBestTrial ); + return pNtkNew; +} + +static Abc_Obj_t * Emap_ManBuildConst( Abc_Ntk_t * pNtkNew, Vec_Int_t * vCopy, int ObjId, int Phase ) +{ + Abc_Obj_t * pObj; + int Entry = Vec_IntEntry( vCopy, 2 * ObjId + Phase ); + if ( Entry >= 0 ) + return Abc_NtkObj( pNtkNew, Entry ); + pObj = Phase ? Abc_NtkCreateNodeConst0( pNtkNew ) : Abc_NtkCreateNodeConst1( pNtkNew ); + Vec_IntWriteEntry( vCopy, 2 * ObjId + Phase, Abc_ObjId(pObj) ); + return pObj; +} + +static Abc_Obj_t * Emap_ManBuildPhase_rec( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew, Emap_Obj_t * pMaps, Vec_Int_t * vCopy, int ObjId, int Phase, Emap_Lib_t * pLib ) +{ + Emap_Obj_t * pMap = &pMaps[ObjId]; + Emap_Best_t * pBest = &pMap->Best[Phase]; + Emap_Cut_t * pCut; + Abc_Obj_t * pObj, * pFanin; + int i, Entry = Vec_IntEntry( vCopy, 2 * ObjId + Phase ); + if ( Entry >= 0 ) + return Abc_NtkObj( pNtkNew, Entry ); + if ( ObjId == Abc_ObjId(Abc_AigConst1(pNtk)) ) + return Emap_ManBuildConst( pNtkNew, vCopy, ObjId, Phase ); + if ( Abc_ObjIsPi(Abc_NtkObj(pNtk, ObjId)) ) + { + Entry = Vec_IntEntry( vCopy, 2 * ObjId + 0 ); + assert( Entry >= 0 ); + if ( Phase == 0 ) + return Abc_NtkObj( pNtkNew, Entry ); + pObj = Emap_ManCreateInv( pNtkNew, Abc_NtkObj(pNtkNew, Entry), pLib->pGateInv ); + Vec_IntWriteEntry( vCopy, 2 * ObjId + 1, Abc_ObjId(pObj) ); + return pObj; + } + if ( pBest->fInv ) + { + pFanin = Emap_ManBuildPhase_rec( pNtk, pNtkNew, pMaps, vCopy, ObjId, !Phase, pLib ); + if ( pFanin == NULL ) + return NULL; + pObj = Emap_ManCreateInv( pNtkNew, pFanin, pLib->pGateInv ); + Vec_IntWriteEntry( vCopy, 2 * ObjId + Phase, Abc_ObjId(pObj) ); + return pObj; + } + if ( pBest->TwinObj >= 0 ) + { + Emap_Best_t * pTwinBest = &pMaps[pBest->TwinObj].Best[pBest->TwinPhase]; + Abc_Obj_t * pFanins[EMAP_LEAF_MAX]; + Abc_Obj_t * pObjTwin; + int fCurrentFirst = pBest->pGate <= pTwinBest->pGate; + pCut = &pMap->Cuts[pBest->Cut]; + for ( i = 0; i < pBest->nPins; i++ ) + { + pFanins[i] = Emap_ManBuildPhase_rec( pNtk, pNtkNew, pMaps, vCopy, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i], pLib ); + if ( pFanins[i] == NULL ) + return NULL; + } + pObj = Abc_NtkCreateNode( pNtkNew ); + pObjTwin = Abc_NtkCreateNode( pNtkNew ); + pObj->pData = fCurrentFirst ? pBest->pGate : pTwinBest->pGate; + pObjTwin->pData = fCurrentFirst ? pTwinBest->pGate : pBest->pGate; + for ( i = 0; i < pBest->nPins; i++ ) + { + Abc_ObjAddFanin( pObj, pFanins[i] ); + Abc_ObjAddFanin( pObjTwin, pFanins[i] ); + } + if ( fCurrentFirst ) + { + Vec_IntWriteEntry( vCopy, 2 * ObjId + Phase, Abc_ObjId(pObj) ); + Vec_IntWriteEntry( vCopy, 2 * pBest->TwinObj + pBest->TwinPhase, Abc_ObjId(pObjTwin) ); + return pObj; + } + Vec_IntWriteEntry( vCopy, 2 * pBest->TwinObj + pBest->TwinPhase, Abc_ObjId(pObj) ); + Vec_IntWriteEntry( vCopy, 2 * ObjId + Phase, Abc_ObjId(pObjTwin) ); + return pObjTwin; + } + if ( pBest->pGate == NULL ) + return NULL; + pCut = &pMap->Cuts[pBest->Cut]; + pObj = Abc_NtkCreateNode( pNtkNew ); + pObj->pData = pBest->pGate; + for ( i = 0; i < pBest->nPins; i++ ) + { + pFanin = Emap_ManBuildPhase_rec( pNtk, pNtkNew, pMaps, vCopy, pCut->Leaves[pBest->PinToLeaf[i]], pBest->PinPhase[i], pLib ); + if ( pFanin == NULL ) + return NULL; + Abc_ObjAddFanin( pObj, pFanin ); + } + Vec_IntWriteEntry( vCopy, 2 * ObjId + Phase, Abc_ObjId(pObj) ); + return pObj; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END diff --git a/src/map/emap/module.make b/src/map/emap/module.make new file mode 100644 index 000000000..261e0879e --- /dev/null +++ b/src/map/emap/module.make @@ -0,0 +1,2 @@ +SRC += src/map/emap/emap.c \ + src/map/emap/emapCore.c diff --git a/src/map/scl/sclDnsize.c b/src/map/scl/sclDnsize.c index 35f2c8247..20ffebb6f 100644 --- a/src/map/scl/sclDnsize.c +++ b/src/map/scl/sclDnsize.c @@ -149,7 +149,7 @@ p->timeSize += Abc_Clock() - clk; { pCellNew = SC_LibCell( p->pLib, gateBest ); Abc_SclObjSetCell( pObj, pCellNew ); - p->SumArea += pCellNew->area - pCellOld->area; + p->SumArea += Abc_SclObjAreaDelta( pObj, pCellOld, pCellNew ); // printf( "%f %f -> %f\n", pCellNew->area - pCellOld->area, p->SumArea - (pCellNew->area - pCellOld->area), p->SumArea ); // printf( "%6d %20s -> %20s %f -> %f\n", Abc_ObjId(pObj), pCellOld->pName, pCellNew->pName, pCellOld->area, pCellNew->area ); // mark used nodes with the current trav ID @@ -376,4 +376,3 @@ void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, ABC_NAMESPACE_IMPL_END - diff --git a/src/map/scl/sclLib.h b/src/map/scl/sclLib.h index b50e6ffb7..eb2d7920d 100644 --- a/src/map/scl/sclLib.h +++ b/src/map/scl/sclLib.h @@ -656,12 +656,13 @@ static inline void Scl_LibPinRequiredI( SC_Timing * pTime, SC_PairI * pReqIn, SC SeeAlso [] ***********************************************************************/ -static inline SC_Timing * Scl_CellPinTime( SC_Cell * pCell, int iPin ) +static inline SC_Timing * Scl_CellPinOutTime( SC_Cell * pCell, int iOut, int iPin ) { SC_Pin * pPin; SC_Timings * pRTime; + assert( iOut >= 0 && iOut < pCell->n_outputs ); assert( iPin >= 0 && iPin < pCell->n_inputs ); - pPin = SC_CellPin( pCell, pCell->n_inputs ); + pPin = SC_CellPin( pCell, pCell->n_inputs + iOut ); assert( Vec_PtrSize(&pPin->vRTimings) == pCell->n_inputs ); pRTime = (SC_Timings *)Vec_PtrEntry( &pPin->vRTimings, iPin ); if ( Vec_PtrSize(&pRTime->vTimings) == 0 ) @@ -669,6 +670,10 @@ static inline SC_Timing * Scl_CellPinTime( SC_Cell * pCell, int iPin ) assert( Vec_PtrSize(&pRTime->vTimings) == 1 ); return (SC_Timing *)Vec_PtrEntry( &pRTime->vTimings, 0 ); } +static inline SC_Timing * Scl_CellPinTime( SC_Cell * pCell, int iPin ) +{ + return Scl_CellPinOutTime( pCell, 0, iPin ); +} static inline float Scl_LibPinArrivalEstimate( SC_Cell * pCell, int iPin, float Slew, float Load ) { SC_Pair LoadIn = { Load, Load }; diff --git a/src/map/scl/sclSize.c b/src/map/scl/sclSize.c index bf2a40090..8d3a2dd5a 100644 --- a/src/map/scl/sclSize.c +++ b/src/map/scl/sclSize.c @@ -103,6 +103,35 @@ Abc_Obj_t * Abc_SclFindMostCriticalFanin( SC_Man * p, int * pfRise, Abc_Obj_t * return pPivot; } +/**Function************************************************************* + + Synopsis [Find the output pin represented by this mapped node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Abc_SclObjOutputIndex( Abc_Obj_t * pObj, SC_Cell * pCell ) +{ + Mio_Gate_t * pGate; + char * pOutName; + int i; + if ( pCell->n_outputs == 1 ) + return 0; + pGate = (Mio_Gate_t *)pObj->pData; + assert( pGate != NULL ); + pOutName = Mio_GateReadOutName( pGate ); + assert( pOutName != NULL ); + for ( i = 0; i < pCell->n_outputs; i++ ) + if ( !strcmp( pOutName, SC_CellPinName(pCell, pCell->n_inputs + i) ) ) + return i; + assert( 0 ); + return 0; +} + /**Function************************************************************* Synopsis [Printing timing information for the node/network.] @@ -299,10 +328,20 @@ static inline void Abc_SclDeptObj( SC_Man * p, Abc_Obj_t * pObj ) SC_PairClean( Abc_SclObjDept(p, pObj) ); Abc_ObjForEachFanout( pObj, pFanout, i ) { + SC_Cell * pFanoutCell; + int iFanin, iOut; if ( Abc_ObjIsCo(pFanout) || Abc_ObjIsLatch(pFanout) ) continue; - pTime = Scl_CellPinTime( Abc_SclObjCell(pFanout), Abc_NodeFindFanin(pFanout, pObj) ); - Abc_SclDeptFanin( p, pTime, pFanout, pObj, Abc_NodeFindFanin(pFanout, pObj) ); + pFanoutCell = Abc_SclObjCell( pFanout ); + iFanin = Abc_NodeFindFanin( pFanout, pObj ); + iOut = Abc_SclObjOutputIndex( pFanout, pFanoutCell ); + pTime = Scl_CellPinOutTime( pFanoutCell, iOut, iFanin ); + if ( pTime == NULL ) + { + assert( pFanoutCell->n_outputs > 1 ); + continue; + } + Abc_SclDeptFanin( p, pTime, pFanout, pObj, iFanin ); } } static inline float Abc_SclObjLoadValue( SC_Man * p, Abc_Obj_t * pObj ) @@ -370,7 +409,13 @@ void Abc_SclTimeNode( SC_Man * p, Abc_Obj_t * pObj, int fDept ) // compute for each fanin Abc_ObjForEachFanin( pObj, pFanin, k ) { - pTime = Scl_CellPinTime( pCell, k ); + int iOut = Abc_SclObjOutputIndex( pObj, pCell ); + pTime = Scl_CellPinOutTime( pCell, iOut, k ); + if ( pTime == NULL ) + { + assert( pCell->n_outputs > 1 ); + continue; + } if ( fDept ) Abc_SclDeptFanin( p, pTime, pObj, pFanin, k ); else @@ -928,4 +973,3 @@ void Abc_SclPrintBuffers( SC_Lib * pLib, Abc_Ntk_t * pNtk, int fVerbose ) ABC_NAMESPACE_IMPL_END - diff --git a/src/map/scl/sclSize.h b/src/map/scl/sclSize.h index 133ae6647..acb66bb9c 100644 --- a/src/map/scl/sclSize.h +++ b/src/map/scl/sclSize.h @@ -27,6 +27,7 @@ //////////////////////////////////////////////////////////////////////// #include "base/abc/abc.h" +#include "map/mio/mio.h" #include "misc/vec/vecQue.h" #include "misc/vec/vecWec.h" #include "sclLib.h" @@ -130,6 +131,64 @@ static inline float Abc_SclObjInDrive( SC_Man * p, Abc_Obj_t * pObj ) static inline void Abc_SclObjSetInDrive( SC_Man * p, Abc_Obj_t * pObj, float c){ Vec_FltWriteEntry( p->vInDrive, pObj->iData, c ); } static inline void Abc_SclManSetFaninCallBack( SC_Man * p, void * pCallBack ) { p->pFuncFanin = (float (*)(void *, Abc_Obj_t *, Abc_Obj_t *, int, int))pCallBack; } +static inline int Abc_SclObjsHaveSameFanins( Abc_Obj_t * pObj0, Abc_Obj_t * pObj1 ) +{ + Abc_Obj_t * pFanin0, * pFanin1; + int i; + if ( pObj0 == NULL || pObj1 == NULL || Abc_ObjFaninNum(pObj0) != Abc_ObjFaninNum(pObj1) ) + return 0; + Abc_ObjForEachFanin( pObj0, pFanin0, i ) + { + pFanin1 = Abc_ObjFanin( pObj1, i ); + if ( pFanin0 != pFanin1 ) + return 0; + } + return 1; +} +static inline int Abc_SclObjIsMogOutput( Abc_Obj_t * pObj ) +{ + Mio_Gate_t * pGate; + if ( pObj == NULL || !Abc_ObjIsNode(pObj) ) + return 0; + pGate = (Mio_Gate_t *)pObj->pData; + return pGate != NULL && Mio_GateReadTwin(pGate) != NULL; +} +static inline int Abc_SclObjIsSecondTwin( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pPrev; + Mio_Gate_t * pGate; + if ( !Abc_SclObjIsMogOutput(pObj) || Abc_ObjId(pObj) == 0 ) + return 0; + pPrev = Abc_NtkObj( pObj->pNtk, Abc_ObjId(pObj) - 1 ); + if ( pPrev == NULL || !Abc_ObjIsNode(pPrev) ) + return 0; + pGate = (Mio_Gate_t *)pObj->pData; + if ( Mio_GateReadTwin(pGate) != (Mio_Gate_t *)pPrev->pData ) + return 0; + return Abc_SclObjsHaveSameFanins( pObj, pPrev ); +} +static inline Abc_Obj_t * Abc_SclObjTwin( Abc_Obj_t * pObj ) +{ + if ( Abc_SclObjIsSecondTwin(pObj) ) + return Abc_NtkObj( pObj->pNtk, Abc_ObjId(pObj) - 1 ); + return Abc_NtkFetchTwinNode( pObj ); +} +static inline int Abc_SclObjTwinFaninsMatch( Abc_Obj_t * pObj ) +{ + Abc_Obj_t * pTwin = Abc_SclObjTwin( pObj ); + return pTwin != NULL && Abc_SclObjsHaveSameFanins( pObj, pTwin ); +} +static inline int Abc_SclObjIsCanonicalMog( Abc_Obj_t * pObj ) +{ + return Abc_SclObjIsMogOutput(pObj) && !Abc_SclObjIsSecondTwin(pObj); +} +static inline float Abc_SclObjAreaDelta( Abc_Obj_t * pObj, SC_Cell * pCellOld, SC_Cell * pCellNew ) +{ + if ( Abc_SclObjIsSecondTwin(pObj) ) + return 0.0; + return pCellNew->area - pCellOld->area; +} + //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// @@ -450,7 +509,11 @@ static inline float Abc_SclGetTotalArea( Abc_Ntk_t * pNtk ) Abc_Obj_t * pObj; int i; Abc_NtkForEachNodeNotBarBuf1( pNtk, pObj, i ) + { + if ( Abc_SclObjIsSecondTwin(pObj) ) + continue; Area += Abc_SclObjCell(pObj)->area; + } return Area; } static inline float Abc_SclGetMaxDelay( SC_Man * p ) diff --git a/src/map/scl/sclUpsize.c b/src/map/scl/sclUpsize.c index 822278a33..fbc3290af 100644 --- a/src/map/scl/sclUpsize.c +++ b/src/map/scl/sclUpsize.c @@ -489,7 +489,7 @@ int Abc_SclFindBypasses( SC_Man * p, Vec_Int_t * vPathNodes, int Ratio, int Notc // update cell pCellOld = Abc_SclObjCell( pFanin ); pCellNew = SC_LibCell( p->pLib, Vec_IntEntry(p->vNode2Gate, iNode) ); - p->SumArea += pCellNew->area - pCellOld->area; + p->SumArea += Abc_SclObjAreaDelta( pFanin, pCellOld, pCellNew ); Abc_SclObjSetCell( pFanin, pCellNew ); Abc_SclUpdateLoad( p, pFanin, pCellOld, pCellNew ); // record the update @@ -646,7 +646,7 @@ int Abc_SclFindUpsizes( SC_Man * p, Vec_Int_t * vPathNodes, int Ratio, int Notch //printf( "gain is %f\n", Vec_FltEntry(p->vNode2Gain, Abc_ObjId(pObj)) ); // update gate Abc_SclUpdateLoad( p, pObj, pCellOld, pCellNew ); - p->SumArea += pCellNew->area - pCellOld->area; + p->SumArea += Abc_SclObjAreaDelta( pObj, pCellOld, pCellNew ); Abc_SclObjSetCell( pObj, pCellNew ); // record the update Vec_IntPush( p->vUpdates, Abc_ObjId(pObj) ); @@ -686,7 +686,7 @@ return Limit; // if ( pCellOld->Order > 0 ) // printf( "%.2f %d -> %d(%d) ", Vec_FltEntry(p->vNode2Gain, iNode), pCellOld->Order, pCellNew->Order, pCellNew->nGates ); // update gate - p->SumArea += pCellNew->area - pCellOld->area; + p->SumArea += Abc_SclObjAreaDelta( pObj, pCellOld, pCellNew ); Abc_SclObjSetCell( pObj, pCellNew ); Abc_SclUpdateLoad( p, pObj, pCellOld, pCellNew ); // record the update @@ -1043,4 +1043,3 @@ void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, ABC_NAMESPACE_IMPL_END - diff --git a/src/map/scl/sclUtil.c b/src/map/scl/sclUtil.c index 0deb0f0fd..331dedb5c 100644 --- a/src/map/scl/sclUtil.c +++ b/src/map/scl/sclUtil.c @@ -75,9 +75,11 @@ void Abc_SclSclGates2MioGates( SC_Lib * pLib, Abc_Ntk_t * p ) assert( p->vGates != NULL ); Abc_NtkForEachNodeNotBarBuf1( p, pObj, i ) { + Mio_Gate_t * pGateOld = (Mio_Gate_t *)pObj->pData; + char * pOutName = Abc_SclObjIsMogOutput(pObj) ? Mio_GateReadOutName(pGateOld) : NULL; pCell = Abc_SclObjCell(pObj); assert( pCell->n_inputs == Abc_ObjFaninNum(pObj) ); - pObj->pData = Mio_LibraryReadGateByName( (Mio_Library_t *)p->pManFunc, pCell->pName, NULL ); + pObj->pData = Mio_LibraryReadGateByName( (Mio_Library_t *)p->pManFunc, pCell->pName, pOutName ); Counter += (pObj->pData == NULL); assert( pObj->fMarkA == 0 && pObj->fMarkB == 0 ); CounterAll++; @@ -317,4 +319,3 @@ void Abc_SclInsertBarBufs( Abc_Ntk_t * pNtk, Vec_Int_t * vBufs ) ABC_NAMESPACE_IMPL_END - diff --git a/src/misc/extra/extraUtilFile.c b/src/misc/extra/extraUtilFile.c index 6585b7a72..480280f3c 100644 --- a/src/misc/extra/extraUtilFile.c +++ b/src/misc/extra/extraUtilFile.c @@ -23,6 +23,9 @@ #define PATH_MAX MAX_PATH #else #include +# ifndef PATH_MAX +# define PATH_MAX 4096 +# endif #endif #include "extra.h" diff --git a/src/opt/fret/fretMain.c b/src/opt/fret/fretMain.c index f742cda03..e7995bf52 100644 --- a/src/opt/fret/fretMain.c +++ b/src/opt/fret/fretMain.c @@ -202,8 +202,9 @@ Abc_FlowRetime_MinReg( Abc_Ntk_t * pNtk, int fVerbose, pNtk = Abc_FlowRetime_NtkSilentRestrash( pNtk, 1 ); } + i = Abc_NtkLevel(pNtk); vprintf("\tfinal reg count = %d\n", Abc_NtkLatchNum(pNtk)); - vprintf("\tfinal levels = %d\n", Abc_NtkLevel(pNtk)); + vprintf("\tfinal levels = %d\n", i); #if defined(DEBUG_CHECK) Abc_NtkDoCheck( pNtk ); @@ -1380,4 +1381,3 @@ void Abc_ObjPrintNeighborhood( Abc_Obj_t *pObj, int depth ) { Vec_PtrFree(vNodes); } ABC_NAMESPACE_IMPL_END - diff --git a/src/opt/fret/fretTime.c b/src/opt/fret/fretTime.c index 9d55fc929..67fcabf8c 100644 --- a/src/opt/fret/fretTime.c +++ b/src/opt/fret/fretTime.c @@ -94,14 +94,13 @@ void Abc_FlowRetime_ConstrainConserv( Abc_Ntk_t * pNtk ) { // clear all exact constraints pManMR->nExactConstraints = 0; - while( Vec_PtrSize( pManMR->vExactNodes )) { - pObj = (Abc_Obj_t*)Vec_PtrPop( pManMR->vExactNodes ); - + Abc_NtkForEachObj( pNtk, pObj, i ) { if ( Vec_PtrSize( FTIMEEDGES(pObj) )) { pArray = Vec_PtrReleaseArray( FTIMEEDGES(pObj) ); ABC_FREE( pArray ); } } + Vec_PtrClear( pManMR->vExactNodes ); #if !defined(IGNORE_TIMING) if (pManMR->fIsForward) { diff --git a/src/opt/lpk/lpkCut.c b/src/opt/lpk/lpkCut.c index 41cfaed5f..f19decff0 100644 --- a/src/opt/lpk/lpkCut.c +++ b/src/opt/lpk/lpkCut.c @@ -141,7 +141,7 @@ unsigned * Lpk_CutTruth_rec( Hop_Man_t * pMan, Hop_Obj_t * pObj, int nVars, Vec_ assert( !Hop_IsComplement(pObj) ); if ( pObj->pData ) { - assert( ((unsigned)(ABC_PTRUINT_T)pObj->pData) & 0xffff0000 ); + assert( ((ABC_PTRUINT_T)pObj->pData) > 0xffff ); // catch small int values return (unsigned *)pObj->pData; } // get the plan for a new truth table @@ -197,7 +197,7 @@ unsigned * Lpk_CutTruth( Lpk_Man_t * p, Lpk_Cut_t * pCut, int fInv ) // set the initial truth tables at the fanins Abc_ObjForEachFanin( pObj, pFanin, k ) { - assert( ((unsigned)(ABC_PTRUINT_T)pFanin->pCopy) & 0xffff0000 ); + assert( ((ABC_PTRUINT_T)pFanin->pCopy) > 0xffff ); // catch small int values or NULL Hop_ManPi( pManHop, k )->pData = pFanin->pCopy; } // compute the truth table of internal nodes diff --git a/src/opt/ufar/UfarCmd.cpp b/src/opt/ufar/UfarCmd.cpp index f4bd70b20..6270cbb59 100755 --- a/src/opt/ufar/UfarCmd.cpp +++ b/src/opt/ufar/UfarCmd.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "base/wlc/wlc.h" #include "aig/gia/giaAig.h" @@ -30,6 +31,22 @@ ABC_NAMESPACE_IMPL_START using namespace std; static UFAR::UfarManager ufar_manager; +typedef struct Ufar_StopCtx_t_ +{ + int (*pFuncStop)(int); + int nTimeOut; + int fActive; + timeval TimeStart; +} Ufar_StopCtx_t; +#if defined(_MSC_VER) +__declspec(thread) static Ufar_StopCtx_t g_UfarStopCtx = { NULL, 0, 0, {0, 0} }; +#elif defined(__cplusplus) && __cplusplus >= 201103L +static thread_local Ufar_StopCtx_t g_UfarStopCtx = { NULL, 0, 0, {0, 0} }; +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +static _Thread_local Ufar_StopCtx_t g_UfarStopCtx = { NULL, 0, 0, {0, 0} }; +#else +static __thread Ufar_StopCtx_t g_UfarStopCtx = { NULL, 0, 0, {0, 0} }; +#endif static int Abc_CommandTest( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAnalyzeCex( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -40,6 +57,38 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv static inline Wlc_Ntk_t * Wlc_AbcGetNtk( Abc_Frame_t * pAbc ) { return (Wlc_Ntk_t *)pAbc->pAbcWlc; } static inline void Wlc_AbcFreeNtk( Abc_Frame_t * pAbc ) { if ( pAbc->pAbcWlc ) Wlc_NtkFree(Wlc_AbcGetNtk(pAbc)); } static inline void Wlc_AbcUpdateNtk( Abc_Frame_t * pAbc, Wlc_Ntk_t * pNtk ) { Wlc_AbcFreeNtk(pAbc); pAbc->pAbcWlc = pNtk; } +static inline long long Ufar_ElapsedUsec( const timeval & Start, const timeval & Stop ) { return 1000000ll * (long long)(Stop.tv_sec - Start.tv_sec) + (long long)(Stop.tv_usec - Start.tv_usec); } + +static int Ufar_StopWithTimeout( int RunId ) +{ + if ( g_UfarStopCtx.pFuncStop && g_UfarStopCtx.pFuncStop(RunId) ) + return 1; + if ( g_UfarStopCtx.fActive && g_UfarStopCtx.nTimeOut > 0 ) + { + timeval Now; + gettimeofday( &Now, NULL ); + if ( Ufar_ElapsedUsec(g_UfarStopCtx.TimeStart, Now) >= 1000000ll * (long long)g_UfarStopCtx.nTimeOut ) + return 1; + } + return 0; +} + +struct Ufar_StopScope_t +{ + Ufar_StopCtx_t Saved; + Ufar_StopScope_t( int (*pFuncStop)(int), int nTimeOut ) + { + Saved = g_UfarStopCtx; + g_UfarStopCtx.pFuncStop = pFuncStop; + g_UfarStopCtx.nTimeOut = nTimeOut; + g_UfarStopCtx.fActive = 1; + gettimeofday( &g_UfarStopCtx.TimeStart, NULL ); + } + ~Ufar_StopScope_t() + { + g_UfarStopCtx = Saved; + } +}; static string Ufar_GetStatusName( Wlc_Ntk_t * pNtk ) { @@ -74,6 +123,292 @@ static void Ufar_DumpStatusLog( const string & FileName, int RetValue, const str fclose( pFile ); } +static void Ufar_SetDefaultParams( UFAR::UfarManager::Params & Params, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId ) +{ + Params = UFAR::UfarManager::Params(); + Params.RunId = RunId; + Params.pFuncStop = pFuncStop; + if ( nTimeOut > 0 ) + Params.nTimeout = nTimeOut; + Params.iVerbosity = fVerbose ? 1 : 0; +} +static void Ufar_AddOptions( OptMgr & opt_mgr, const UFAR::UfarManager::Params & Params ) +{ + opt_mgr.AddOpt("--norm", Params.fNorm ? "yes" : "no", "", "toggle using data type normalization"); + opt_mgr.AddOpt("--adder", "no", "", "toggle including adders"); + opt_mgr.AddOpt("--cexmin", Params.fCexMin ? "yes" : "no", "", "toggle using CEX minimization"); + opt_mgr.AddOpt("--sim", "none", "str", "use simulation and specify its setting"); + opt_mgr.AddOpt("-v", to_string(Params.iVerbosity), "num", "specify verbosity level"); + opt_mgr.AddOpt("--seq", to_string(Params.nSeqLookBack), "num", "specify the number of look-back frames (0 = no sequential UIF)"); + opt_mgr.AddOpt("--profile", "no", "", "dump time distribution"); + opt_mgr.AddOpt("--pba_uif", Params.fPbaUif ? "yes" : "no", "", "toggle using proof-based refinement for UIF pairs"); + opt_mgr.AddOpt("--lazysim", Params.fLazySim ? "yes" : "no", "", "toggle applying UIF pairs based on simulation"); + opt_mgr.AddOpt("--pbasim", Params.fPbaSim ? "yes" : "no", "", "toggle combining pba and sim"); + opt_mgr.AddOpt("--pbacex", Params.fPbaCex ? "yes" : "no", "", "toggle combining pba and cex"); + opt_mgr.AddOpt("--satmin", Params.fSatMin ? "yes" : "no", "", "toggle using sat-min in pba"); + opt_mgr.AddOpt("--cbawb", Params.fCbaWb ? "yes" : "no", "", "toggle using cex-based refinement for white boxing"); + opt_mgr.AddOpt("--grey", Params.fGrey ? "yes" : "no", "", "toggle using grey-box constraints"); + opt_mgr.AddOpt("--grey2", to_string(Params.nGrey), "float", "specify the greyness threshold"); + opt_mgr.AddOpt("--allwb", Params.fAllWb ? "yes" : "no", "", "start with all operators white-boxed (no initial abstraction)"); + opt_mgr.AddOpt("--crossonly", Params.fCrossOnly ? "yes" : "no", "", "allow UIF pairs only across LHS/RHS cones of the miter"); + opt_mgr.AddOpt("--crossstats", "no", "", "print multiplier counts in LHS/RHS/shared cones and exit"); + opt_mgr.AddOpt("--dump", "none", "str", "specify file name"); + opt_mgr.AddOpt("--dump-log", "none", "str", "write status log"); + opt_mgr.AddOpt("--dump-first-aig", "none", "str", "dump first internal bit-blasted AIG and exit"); + opt_mgr.AddOpt("--dump-abs", "none", "str", "specify file name"); + opt_mgr.AddOpt("--par", "none", "str", "use parallel solvers"); + opt_mgr.AddOpt("--solver", "none", "str", "external solver command line"); + opt_mgr.AddOpt("--dump_states", "none", "str", "specify the name for the states file"); + opt_mgr.AddOpt("--read_states", "none", "str", "specify the name for the states file"); + opt_mgr.AddOpt("--sp", Params.fSuper_prove ? "yes" : "no", "", "toggle using super_prove"); + opt_mgr.AddOpt("--simp", Params.fSimple ? "yes" : "no", "", "toggle using simple (prove)"); + opt_mgr.AddOpt("--syn", Params.fSyn ? "yes" : "no", "", "toggle using simple synthesis"); + opt_mgr.AddOpt("--pth", Params.fPthread ? "yes" : "no", "", "toggle using pthreads"); + opt_mgr.AddOpt("--onewb", to_string(Params.iOneWb), "int", "specify the mode for one-white-boxing"); + opt_mgr.AddOpt("--initallpairs", to_string(Params.nInitAllPairsLimit), "num", "pre-seed all compatible UIF pairs when #ops <= this limit (0=off)"); + opt_mgr.AddOpt("--initnear", to_string(Params.nInitNearMults), "num", "pre-seed UIF pairs among up to this many multipliers closest to output"); + opt_mgr.AddOpt("--timeout", to_string(Params.nTimeout), "num", "specify the timeout (sec)"); + opt_mgr.AddOpt("--exp", to_string(Params.iExp), "int", "specify the exp mode"); + opt_mgr.AddOpt("--miter", "yes", "", "toggle mitering the problem"); + opt_mgr.AddOpt("--under", "-1", "num", "try under-approximation with the given size"); +} +static void Ufar_ApplyOptions( OptMgr & opt_mgr, UFAR::UfarManager::Params & Params, set & set_op_types, string & firstAigDumpFile, string & dumpLogFile, int & fNeedMiter, int & fCrossStats, int & UnderSize ) +{ + firstAigDumpFile = ""; + dumpLogFile = opt_mgr["--dump-log"] ? opt_mgr.GetOptVal("--dump-log") : ""; + fNeedMiter = !opt_mgr["--miter"]; + fCrossStats = opt_mgr["--crossstats"] ? 1 : 0; + UnderSize = opt_mgr["--under"] ? stoi(opt_mgr.GetOptVal("--under")) : -1; + + if(opt_mgr["--norm"]) + Params.fNorm ^= 1; + if(opt_mgr["--cexmin"]) + Params.fCexMin ^= 1; + if(opt_mgr["--pba_uif"]) + Params.fPbaUif ^= 1; + if(opt_mgr["--pbasim"]) + Params.fPbaSim ^= 1; + if(opt_mgr["--pbacex"]) + Params.fPbaCex ^= 1; + if(opt_mgr["--satmin"]) + Params.fSatMin ^= 1; + if(opt_mgr["--cbawb"]) + Params.fCbaWb ^= 1; + if(opt_mgr["--grey"]) + Params.fGrey ^= 1; + if(opt_mgr["--allwb"]) + Params.fAllWb ^= 1; + if(opt_mgr["--crossonly"]) + Params.fCrossOnly ^= 1; + if(opt_mgr["--grey2"]) + Params.nGrey = stof(opt_mgr.GetOptVal("--grey2")); + if(opt_mgr["--sp"]) + Params.fSuper_prove ^= 1; + if(opt_mgr["--simp"]) + Params.fSimple ^= 1; + if(opt_mgr["--syn"]) + Params.fSyn ^= 1; + if(opt_mgr["--pth"]) + Params.fPthread ^= 1; + if(opt_mgr["--onewb"]) + Params.iOneWb = stoi(opt_mgr.GetOptVal("--onewb")); + if(opt_mgr["--initallpairs"]) + Params.nInitAllPairsLimit = stoi(opt_mgr.GetOptVal("--initallpairs")); + if(opt_mgr["--initnear"]) + Params.nInitNearMults = stoi(opt_mgr.GetOptVal("--initnear")); + if(opt_mgr["--exp"]) + Params.iExp = stoi(opt_mgr.GetOptVal("--exp")); + if(opt_mgr["--par"]) + Params.parSetting = opt_mgr.GetOptVal("--par"); + if(opt_mgr["--solver"]) + Params.solverSetting = opt_mgr.GetOptVal("--solver"); + if(opt_mgr["--sim"]) + Params.simSetting = opt_mgr.GetOptVal("--sim"); + if(opt_mgr["--dump_states"]) { + smatch sub_match; + string option = opt_mgr.GetOptVal("--dump_states"); + if(regex_search(option, sub_match, regex(R"(/?(\w+\.v)$)"))) + Params.fileStatesOut = sub_match[1].str(); + else + Params.fileStatesOut = opt_mgr.GetOptVal("--dump_states"); + } + if(opt_mgr["--read_states"]) + Params.fileStatesIn = opt_mgr.GetOptVal("--read_states"); + if(opt_mgr["--lazysim"]) + Params.fLazySim ^= 1; + if(opt_mgr["-v"]) + Params.iVerbosity = stoi(opt_mgr.GetOptVal("-v")); + if(opt_mgr["--timeout"]) + Params.nTimeout = stoi(opt_mgr.GetOptVal("--timeout")); + if(opt_mgr["--seq"]) + Params.nSeqLookBack = stoi(opt_mgr.GetOptVal("--seq")); + if(opt_mgr["--dump-abs"]) { + smatch sub_match; + string option = opt_mgr.GetOptVal("--dump-abs"); + if(regex_search(option, sub_match, regex(R"(/?(\w+)\.v$)"))) + Params.fileAbs = sub_match[1].str(); + else + Params.fileAbs = opt_mgr.GetOptVal("--dump-abs"); + } + if(opt_mgr["--dump"]) { + smatch sub_match; + string option = opt_mgr.GetOptVal("--dump"); + if(regex_search(option, sub_match, regex(R"(/?(\w+\.v)$)"))) + Params.fileName = sub_match[1].str(); + else + Params.fileName = opt_mgr.GetOptVal("--dump"); + } + if ( opt_mgr["--dump-first-aig"] ) + firstAigDumpFile = opt_mgr.GetOptVal("--dump-first-aig"); + set_op_types.insert(WLC_OBJ_ARI_MULTI); + if (opt_mgr["--adder"]) + set_op_types.insert(WLC_OBJ_ARI_ADD); +} +static bool Ufar_TokenizeArgs( const char * pArgs, vector & Tokens ) +{ + string Cur; + char Quote = 0; + if ( pArgs == NULL ) + return true; + for ( ; *pArgs; ++pArgs ) + { + unsigned char c = (unsigned char)*pArgs; + if ( Quote ) + { + if ( c == (unsigned char)Quote ) + Quote = 0; + else if ( c == '\\' && pArgs[1] ) + Cur += *++pArgs; + else + Cur += (char)c; + continue; + } + if ( c == '"' || c == '\'' ) + { + Quote = (char)c; + continue; + } + if ( isspace(c) ) + { + if ( !Cur.empty() ) + { + Tokens.push_back( Cur ); + Cur.clear(); + } + continue; + } + if ( c == '\\' && pArgs[1] ) + { + Cur += *++pArgs; + continue; + } + Cur += (char)c; + } + if ( Quote ) + return false; + if ( !Cur.empty() ) + Tokens.push_back( Cur ); + return true; +} + +static inline void Ufar_TrimString( string & s ) +{ + while ( !s.empty() && isspace((unsigned char)s.front()) ) + s.erase( s.begin() ); + while ( !s.empty() && isspace((unsigned char)s.back()) ) + s.pop_back(); +} + +static bool Ufar_ExtractSolverArg( const char * pArgs, string & ArgsWithoutSolver, string & SolverArg ) +{ + string Args = pArgs ? pArgs : ""; + size_t i = 0, n = Args.size(); + ArgsWithoutSolver = Args; + SolverArg.clear(); + while ( i < n ) + { + while ( i < n && isspace((unsigned char)Args[i]) ) + i++; + if ( i == n ) + break; + size_t TokenStart = i; + char Quote = 0; + string Token; + while ( i < n ) + { + unsigned char c = (unsigned char)Args[i]; + if ( Quote ) + { + if ( c == (unsigned char)Quote ) + Quote = 0; + else if ( c == '\\' && i + 1 < n ) + Token += Args[++i]; + else + Token += (char)c; + i++; + continue; + } + if ( c == '"' || c == '\'' ) + { + Quote = (char)c; + i++; + continue; + } + if ( isspace(c) ) + break; + if ( c == '\\' && i + 1 < n ) + { + Token += Args[++i]; + i++; + continue; + } + Token += (char)c; + i++; + } + if ( Token == "--solver" ) + { + size_t ValueStart = i; + while ( ValueStart < n && isspace((unsigned char)Args[ValueStart]) ) + ValueStart++; + if ( ValueStart == n ) + return false; + string Prefix = Args.substr( 0, TokenStart ); + string Suffix; + if ( Args[ValueStart] == '"' || Args[ValueStart] == '\'' ) + { + char ValueQuote = Args[ValueStart++]; + size_t k = ValueStart; + while ( k < n ) + { + unsigned char c = (unsigned char)Args[k]; + if ( c == (unsigned char)ValueQuote ) + { + k++; + break; + } + if ( c == '\\' && k + 1 < n ) + SolverArg += Args[++k]; + else + SolverArg += (char)c; + k++; + } + Suffix = Args.substr( k ); + } + else + { + SolverArg = Args.substr( ValueStart ); + } + Ufar_TrimString( SolverArg ); + ArgsWithoutSolver = Prefix + Suffix; + Ufar_TrimString( ArgsWithoutSolver ); + return !SolverArg.empty(); + } + while ( i < n && isspace((unsigned char)Args[i]) ) + i++; + } + return false; +} + void Ufar_Init(Abc_Frame_t *pAbc) { @@ -84,39 +419,169 @@ void Ufar_Init(Abc_Frame_t *pAbc) //Cmd_CommandAdd( pAbc, "Word level Prove", "%%miter", Abc_CommandCreateMiter, 0 ); } -int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId ) +int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId, const char * pArgs ) { UFAR::UfarManager manager; timeval t1; + vector Tokens; + vector Argv; set set_op_types; - Wlc_Ntk_t * pUse = pNtk; + string ArgsWithoutSolver, SolverArg; + string firstAigDumpFile, dumpLogFile; + string statusName; + int fNeedMiter = 1, fCrossStats = 0, UnderSize = -1; + Wlc_Ntk_t * pUse = pNtk, * pNew = NULL; int RetValue = -1; if ( pNtk == NULL ) return -1; - if ( Wlc_NtkPoNum(pUse) == 2 ) + Ufar_SetDefaultParams( manager.params, nTimeOut, fVerbose, pFuncStop, RunId ); + if ( pArgs && pArgs[0] ) { - pUse = UFAR::CreateMiter( pUse, 0 ); - if ( pUse == NULL ) + const char * pParseArgs = pArgs; + if ( Ufar_ExtractSolverArg(pArgs, ArgsWithoutSolver, SolverArg) ) + pParseArgs = ArgsWithoutSolver.c_str(); + OptMgr opt_mgr("%ufar"); + Ufar_AddOptions( opt_mgr, manager.params ); + if ( !Ufar_TokenizeArgs(pParseArgs, Tokens) ) + { + cout << "Cannot parse internal %ufar option string." << endl; return -1; + } + Argv.reserve( Tokens.size() + 1 ); + Argv.push_back( (char *)"%ufar" ); + for ( size_t i = 0; i < Tokens.size(); i++ ) + Argv.push_back( (char *)Tokens[i].c_str() ); + if ( !opt_mgr.Parse((int)Argv.size(), Argv.data()) ) + { + opt_mgr.PrintUsage(); + return -1; + } + Ufar_ApplyOptions( opt_mgr, manager.params, set_op_types, firstAigDumpFile, dumpLogFile, fNeedMiter, fCrossStats, UnderSize ); + if ( !SolverArg.empty() ) + manager.params.solverSetting = SolverArg; + } + else + set_op_types.insert( WLC_OBJ_ARI_MULTI ); + Ufar_StopScope_t StopScope( manager.params.pFuncStop, (int)manager.params.nTimeout ); + manager.params.pFuncStop = Ufar_StopWithTimeout; + if ( fNeedMiter ) + { + if ( Wlc_NtkPoNum(pUse) == 2 ) + { + pNew = UFAR::CreateMiter( pUse, 0 ); + if ( pUse != pNtk ) + Wlc_NtkFree( pUse ); + pUse = pNew; + if ( pUse == NULL ) + return -1; + } + else if ( Wlc_NtkPoNum(pUse) != 1 ) + { + return -1; + } } else if ( Wlc_NtkPoNum(pUse) != 1 ) return -1; - set_op_types.insert( WLC_OBJ_ARI_MULTI ); + statusName = Ufar_GetStatusName( pUse ); + if ( manager.params.fNorm ) + { + pNew = UFAR::NormalizeDataTypes( pUse, set_op_types, true ); + if ( pUse != pNtk ) + Wlc_NtkFree( pUse ); + pUse = pNew; + } + if ( fCrossStats ) + { + Wlc_Ntk_t * pCur = pUse; + if ( Wlc_NtkPoNum(pCur) != 2 ) + { + cout << "CrossStats requires dual outputs before mitering.\n"; + if ( pUse != pNtk ) + Wlc_NtkFree( pUse ); + return -1; + } + int nObjs = Wlc_NtkObjNumMax(pCur); + vector vConeL(nObjs, 0), vConeR(nObjs, 0); + auto mark_cone = [&]( int iStart, vector& vMark ) + { + if ( iStart < 0 || iStart >= nObjs ) + return; + vector stack(1, iStart); + while ( !stack.empty() ) + { + int iObj = stack.back(); + stack.pop_back(); + if ( iObj < 0 || iObj >= nObjs || vMark[iObj] ) + continue; + vMark[iObj] = 1; + Wlc_Obj_t * pObjT = Wlc_NtkObj(pCur, iObj); + if ( pObjT->Type == WLC_OBJ_FO ) + { + Wlc_Obj_t * pFi = Wlc_ObjFo2Fi(pCur, pObjT); + stack.push_back( Wlc_ObjId(pCur, pFi) ); + } + int iFanin, k; + Wlc_ObjForEachFanin( pObjT, iFanin, k ) + stack.push_back(iFanin); + } + }; + int iRootL = Wlc_ObjFaninId0( Wlc_NtkPo(pCur, 0) ); + int iRootR = Wlc_ObjFaninId0( Wlc_NtkPo(pCur, 1) ); + mark_cone(iRootL, vConeL); + mark_cone(iRootR, vConeR); + + int nL = 0, nR = 0, nB = 0, nN = 0; + Wlc_Obj_t * pObjT; int iObj; + Wlc_NtkForEachObj( pCur, pObjT, iObj ) + { + if ( pObjT->Type != WLC_OBJ_ARI_MULTI ) + continue; + bool fL = vConeL[iObj] != 0; + bool fR = vConeR[iObj] != 0; + if ( fL && fR ) nB++; + else if ( fL ) nL++; + else if ( fR ) nR++; + else nN++; + } + cout << "UIF_PROVE : CrossStats: L=" << nL + << " R=" << nR + << " BOTH=" << nB + << " NONE=" << nN + << " TOTAL=" << (nL + nR + nB + nN) << endl; + if ( pUse != pNtk ) + Wlc_NtkFree( pUse ); + return -1; + } if ( !UFAR::HasOperator( pUse, set_op_types ) ) { if ( pUse != pNtk ) Wlc_NtkFree( pUse ); return -1; } - manager.params = UFAR::UfarManager::Params(); - manager.params.RunId = RunId; - manager.params.pFuncStop = pFuncStop; - if ( nTimeOut > 0 ) - manager.params.nTimeout = nTimeOut; - manager.params.iVerbosity = fVerbose ? 1 : 0; + if ( UnderSize >= 0 ) + { + pNew = UFAR::MakeUnderApprox( pUse, UnderSize ); + if ( pUse != pNtk ) + Wlc_NtkFree( pUse ); + pUse = pNew; + pNew = UFAR::MakeUnderApprox2( pUse, set_op_types, UnderSize ); + if ( pUse != pNtk ) + Wlc_NtkFree( pUse ); + pUse = pNew; + } + if ( !firstAigDumpFile.empty() && firstAigDumpFile != "none" ) + { + Gia_Man_t * pGia = UFAR::BitBlast( pUse ); + Gia_AigerWriteSimple( pGia, (char *)firstAigDumpFile.c_str() ); + Gia_ManStop( pGia ); + if ( pUse != pNtk ) + Wlc_NtkFree( pUse ); + return -1; + } gettimeofday( &t1, NULL ); manager.Initialize( pUse, set_op_types ); RetValue = manager.PerformUIFProve( t1 ); + Ufar_DumpStatusLog( dumpLogFile, RetValue, statusName ); if ( pUse != pNtk ) Wlc_NtkFree( pUse ); return RetValue; @@ -160,141 +625,22 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv ufar_manager.params = UFAR::UfarManager::Params(); OptMgr opt_mgr(argv[0]); - opt_mgr.AddOpt("--norm", ufar_manager.params.fNorm ? "yes" : "no", "", "toggle using data type normalization"); - opt_mgr.AddOpt("--adder", "no", "", "toggle including adders"); - opt_mgr.AddOpt("--cexmin", ufar_manager.params.fCexMin ? "yes" : "no", "", "toggle using CEX minimization"); - opt_mgr.AddOpt("--sim", "none", "str", "use simulation and specify its setting"); - opt_mgr.AddOpt("-v", to_string(ufar_manager.params.iVerbosity), "num", "specify verbosity level"); - opt_mgr.AddOpt("--seq", to_string(ufar_manager.params.nSeqLookBack), "num", "specify the number of look-back frames (0 = no sequential UIF)"); - opt_mgr.AddOpt("--profile", "no", "", "dump time distribution"); - opt_mgr.AddOpt("--pba_uif", ufar_manager.params.fPbaUif ? "yes" : "no", "", "toggle using proof-based refinement for UIF pairs"); - opt_mgr.AddOpt("--lazysim", ufar_manager.params.fLazySim ? "yes" : "no", "", "toggle applying UIF pairs based on simulation"); - opt_mgr.AddOpt("--pbasim", ufar_manager.params.fPbaSim ? "yes" : "no", "", "toggle combining pba and sim"); - opt_mgr.AddOpt("--pbacex", ufar_manager.params.fPbaCex ? "yes" : "no", "", "toggle combining pba and cex"); - opt_mgr.AddOpt("--satmin", ufar_manager.params.fSatMin ? "yes" : "no", "", "toggle using sat-min in pba"); - opt_mgr.AddOpt("--cbawb", ufar_manager.params.fCbaWb ? "yes" : "no", "", "toggle using cex-based refinement for white boxing"); - opt_mgr.AddOpt("--grey", ufar_manager.params.fGrey ? "yes" : "no", "", "toggle using grey-box constraints"); - opt_mgr.AddOpt("--grey2", to_string(ufar_manager.params.nGrey), "float", "specify the greyness threshold"); - opt_mgr.AddOpt("--allwb", ufar_manager.params.fAllWb ? "yes" : "no", "", "start with all operators white-boxed (no initial abstraction)"); - opt_mgr.AddOpt("--crossonly", ufar_manager.params.fCrossOnly ? "yes" : "no", "", "allow UIF pairs only across LHS/RHS cones of the miter"); - opt_mgr.AddOpt("--crossstats", "no", "", "print multiplier counts in LHS/RHS/shared cones and exit"); - opt_mgr.AddOpt("--dump", "none", "str", "specify file name"); - opt_mgr.AddOpt("--dump-log", "none", "str", "write status log"); - opt_mgr.AddOpt("--dump-first-aig", "none", "str", "dump first internal bit-blasted AIG and exit"); - opt_mgr.AddOpt("--dump-abs", "none", "str", "specify file name"); - opt_mgr.AddOpt("--par", "none", "str", "use parallel solvers"); - opt_mgr.AddOpt("--solver", "none", "str", "external solver command line"); - opt_mgr.AddOpt("--dump_states", "none", "str", "specify the name for the states file"); - opt_mgr.AddOpt("--read_states", "none", "str", "specify the name for the states file"); - opt_mgr.AddOpt("--sp", ufar_manager.params.fSuper_prove ? "yes" : "no", "", "toggle using super_prove"); - opt_mgr.AddOpt("--simp", ufar_manager.params.fSimple ? "yes" : "no", "", "toggle using simple (prove)"); - opt_mgr.AddOpt("--syn", ufar_manager.params.fSyn ? "yes" : "no", "", "toggle using simple synthesis"); - opt_mgr.AddOpt("--pth", ufar_manager.params.fPthread ? "yes" : "no", "", "toggle using pthreads"); - opt_mgr.AddOpt("--onewb", to_string(ufar_manager.params.iOneWb), "int", "specify the mode for one-white-boxing"); - opt_mgr.AddOpt("--initallpairs", to_string(ufar_manager.params.nInitAllPairsLimit), "num", "pre-seed all compatible UIF pairs when #ops <= this limit (0=off)"); - opt_mgr.AddOpt("--initnear", to_string(ufar_manager.params.nInitNearMults), "num", "pre-seed UIF pairs among up to this many multipliers closest to output"); - opt_mgr.AddOpt("--timeout", to_string(ufar_manager.params.nTimeout), "num", "specify the timeout (sec)"); - opt_mgr.AddOpt("--exp", to_string(ufar_manager.params.iExp), "int", "specify the exp mode"); - opt_mgr.AddOpt("--miter", "yes", "", "toggle mitering the problem"); - opt_mgr.AddOpt("--under", "-1", "num", "try under-approximation with the given size"); + set set_op_types; + string firstAigDumpFile = ""; + string dumpLogFile = ""; + int fNeedMiter = 1, fCrossStats = 0, UnderSize = -1; + Ufar_AddOptions( opt_mgr, ufar_manager.params ); if(!opt_mgr.Parse(argc, argv)) { opt_mgr.PrintUsage(); cout << "\n This command was developed by Yen-Sheng Ho at UC Berkeley in 2015.\n"; cout << " https://people.eecs.berkeley.edu/~alanmi/publications/2016/fmcad16_uif.pdf \n"; return 0; } - - if(opt_mgr["--norm"]) - ufar_manager.params.fNorm ^= 1; - if(opt_mgr["--cexmin"]) - ufar_manager.params.fCexMin ^= 1; - if(opt_mgr["--pba_uif"]) - ufar_manager.params.fPbaUif ^= 1; - if(opt_mgr["--pbasim"]) - ufar_manager.params.fPbaSim ^= 1; - if(opt_mgr["--pbacex"]) - ufar_manager.params.fPbaCex ^= 1; - if(opt_mgr["--satmin"]) - ufar_manager.params.fSatMin ^= 1; - if(opt_mgr["--cbawb"]) - ufar_manager.params.fCbaWb ^= 1; - if(opt_mgr["--grey"]) - ufar_manager.params.fGrey ^= 1; - if(opt_mgr["--allwb"]) - ufar_manager.params.fAllWb ^= 1; - if(opt_mgr["--crossonly"]) - ufar_manager.params.fCrossOnly ^= 1; - if(opt_mgr["--grey2"]) - ufar_manager.params.nGrey = stof(opt_mgr.GetOptVal("--grey2")); - if(opt_mgr["--sp"]) - ufar_manager.params.fSuper_prove ^= 1; - if(opt_mgr["--simp"]) - ufar_manager.params.fSimple ^= 1; - if(opt_mgr["--syn"]) - ufar_manager.params.fSyn ^= 1; - if(opt_mgr["--pth"]) - ufar_manager.params.fPthread ^= 1; - if(opt_mgr["--onewb"]) - ufar_manager.params.iOneWb = stoi(opt_mgr.GetOptVal("--onewb")); - if(opt_mgr["--initallpairs"]) - ufar_manager.params.nInitAllPairsLimit = stoi(opt_mgr.GetOptVal("--initallpairs")); - if(opt_mgr["--initnear"]) - ufar_manager.params.nInitNearMults = stoi(opt_mgr.GetOptVal("--initnear")); - if(opt_mgr["--exp"]) - ufar_manager.params.iExp = stoi(opt_mgr.GetOptVal("--exp")); - if(opt_mgr["--par"]) - ufar_manager.params.parSetting = opt_mgr.GetOptVal("--par"); - if(opt_mgr["--solver"]) - ufar_manager.params.solverSetting = opt_mgr.GetOptVal("--solver"); - if(opt_mgr["--sim"]) - ufar_manager.params.simSetting = opt_mgr.GetOptVal("--sim"); - if(opt_mgr["--dump_states"]) { - smatch sub_match; - string option = opt_mgr.GetOptVal("--dump_states"); - if(regex_search(option, sub_match, regex(R"(/?(\w+\.v)$)"))) - ufar_manager.params.fileStatesOut = sub_match[1].str(); - else - ufar_manager.params.fileStatesOut = opt_mgr.GetOptVal("--dump_states"); - } - if(opt_mgr["--read_states"]) - ufar_manager.params.fileStatesIn = opt_mgr.GetOptVal("--read_states"); - if(opt_mgr["--lazysim"]) - ufar_manager.params.fLazySim ^= 1; - if(opt_mgr["-v"]) - ufar_manager.params.iVerbosity = stoi(opt_mgr.GetOptVal("-v")); - if(opt_mgr["--timeout"]) - ufar_manager.params.nTimeout = stoi(opt_mgr.GetOptVal("--timeout")); - if(opt_mgr["--seq"]) - ufar_manager.params.nSeqLookBack = stoi(opt_mgr.GetOptVal("--seq")); - if(opt_mgr["--dump-abs"]) { - smatch sub_match; - string option = opt_mgr.GetOptVal("--dump-abs"); - if(regex_search(option, sub_match, regex(R"(/?(\w+)\.v$)"))) - ufar_manager.params.fileAbs = sub_match[1].str(); - else - ufar_manager.params.fileAbs = opt_mgr.GetOptVal("--dump-abs"); - } - if(opt_mgr["--dump"]) { - smatch sub_match; - string option = opt_mgr.GetOptVal("--dump"); - if(regex_search(option, sub_match, regex(R"(/?(\w+\.v)$)"))) - ufar_manager.params.fileName = sub_match[1].str(); - else - ufar_manager.params.fileName = opt_mgr.GetOptVal("--dump"); - } - string firstAigDumpFile = ""; - if ( opt_mgr["--dump-first-aig"] ) - firstAigDumpFile = opt_mgr.GetOptVal("--dump-first-aig"); + Ufar_ApplyOptions( opt_mgr, ufar_manager.params, set_op_types, firstAigDumpFile, dumpLogFile, fNeedMiter, fCrossStats, UnderSize ); // ufar_manager.DumpParams(); LogT::prefix = "UIF_PROVE"; - string dumpLogFile = opt_mgr["--dump-log"] ? opt_mgr.GetOptVal("--dump-log") : ""; string statusName = Ufar_GetStatusName( Wlc_AbcGetNtk(pAbc) ); - - set set_op_types; - set_op_types.insert(WLC_OBJ_ARI_MULTI); - if (opt_mgr["--adder"]) - set_op_types.insert(WLC_OBJ_ARI_ADD); if (!UFAR::HasOperator(Wlc_AbcGetNtk(pAbc), set_op_types)) { cout << "There is no operator for UIF.\n"; return 0; @@ -304,7 +650,7 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv timeval t1, t2; gettimeofday(&t1, NULL); - if (!opt_mgr["--miter"]) { + if (fNeedMiter) { if (Wlc_NtkPoNum(Wlc_AbcGetNtk(pAbc)) != 2) { cout << "The current design doesn't have dual outputs.\n"; return 0; @@ -318,7 +664,7 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv Wlc_AbcUpdateNtk(pAbc, pNew); } - if ( opt_mgr["--crossstats"] ) + if ( fCrossStats ) { Wlc_Ntk_t * pCur = Wlc_AbcGetNtk(pAbc); if ( Wlc_NtkPoNum(pCur) != 2 ) @@ -380,10 +726,10 @@ static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv return 0; } - if (opt_mgr["--under"]) { - pNew = UFAR::MakeUnderApprox(Wlc_AbcGetNtk(pAbc), stoi(opt_mgr.GetOptVal("--under"))); + if ( UnderSize >= 0 ) { + pNew = UFAR::MakeUnderApprox(Wlc_AbcGetNtk(pAbc), UnderSize); Wlc_AbcUpdateNtk(pAbc, pNew); - pNew = UFAR::MakeUnderApprox2(Wlc_AbcGetNtk(pAbc), set_op_types, stoi(opt_mgr.GetOptVal("--under"))); + pNew = UFAR::MakeUnderApprox2(Wlc_AbcGetNtk(pAbc), set_op_types, UnderSize); Wlc_AbcUpdateNtk(pAbc, pNew); Wlc_WriteVer(Wlc_AbcGetNtk(pAbc), "UND.v", 0, 0); } diff --git a/src/opt/ufar/UfarCmd.h b/src/opt/ufar/UfarCmd.h index 52dfc8bb8..b44863ca3 100755 --- a/src/opt/ufar/UfarCmd.h +++ b/src/opt/ufar/UfarCmd.h @@ -15,7 +15,7 @@ ABC_NAMESPACE_HEADER_START void Ufar_Init(Abc_Frame_t *pAbc); typedef struct Wlc_Ntk_t_ Wlc_Ntk_t; -extern int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId ); +extern int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId, const char * pArgs ); ABC_NAMESPACE_HEADER_END diff --git a/src/opt/untk/NtkNtk.cpp b/src/opt/untk/NtkNtk.cpp index 22528e4be..6fc3700b3 100755 --- a/src/opt/untk/NtkNtk.cpp +++ b/src/opt/untk/NtkNtk.cpp @@ -805,7 +805,8 @@ Wlc_Ntk_t * AddConstFlops( Wlc_Ntk_t * pNtk, const set& types ) Wlc_Ntk_t * p = Wlc_NtkDupDfsSimple(pNtk); Wlc_NtkCleanCopy( p ); int nOrigObjNum = Wlc_NtkObjNumMax(p); - Wlc_NtkTransferNames( p, pNtk ); + if ( !Wlc_NtkHasNameId(p) && Wlc_NtkHasNameId(pNtk) ) + Wlc_NtkTransferNames( p, pNtk ); Wlc_Obj_t * pObj; int i, iObjConst0; @@ -872,7 +873,8 @@ Wlc_Ntk_t * AddConstFlops( Wlc_Ntk_t * pNtk, const set& types ) ModifyMarkedNodes(p, nOrigObjNum, create_ff_and_mux); Wlc_Ntk_t * pNew = Wlc_NtkDupDfsSimple( p ); - Wlc_NtkTransferNames( pNew, p ); + if ( !Wlc_NtkHasNameId(pNew) && Wlc_NtkHasNameId(p) ) + Wlc_NtkTransferNames( pNew, p ); Wlc_NtkFree( p ); @@ -1058,7 +1060,8 @@ Wlc_Ntk_t * NormalizeDataTypes(Wlc_Ntk_t * p, const set& types, bool f Wlc_Ntk_t *pNtk, *pNew; pNtk = Wlc_NtkDupDfsSimple(p); - Wlc_NtkTransferNames( pNtk, p ); + if ( !Wlc_NtkHasNameId(pNtk) && Wlc_NtkHasNameId(p) ) + Wlc_NtkTransferNames( pNtk, p ); Wlc_Obj_t *pObj; int i, iFanin0, iFanin1; @@ -1117,7 +1120,8 @@ Wlc_Ntk_t * NormalizeDataTypes(Wlc_Ntk_t * p, const set& types, bool f Vec_IntFree(vFanins); pNew = Wlc_NtkDupDfsSimple(pNtk); - Wlc_NtkTransferNames( pNew, pNtk ); + if ( !Wlc_NtkHasNameId(pNew) && Wlc_NtkHasNameId(pNtk) ) + Wlc_NtkTransferNames( pNew, pNtk ); Wlc_NtkFree(pNtk); return pNew; @@ -1266,11 +1270,15 @@ static inline int run_external_solver_on_aig( Abc_Ntk_t * pAbcNtk, const string& Io_Write( pAbcNtk, (char *)pAigFile, IO_FILE_AIGER ); std::remove( "status.txt" ); std::remove( "log.txt" ); - string command = solverCmd; - if ( command.find(pAigFile) == string::npos ) - command += string(" ") + pAigFile; + string solverCall = solverCmd; + string command; + if ( solverCall.find(pAigFile) == string::npos ) + solverCall += string(" ") + pAigFile; if ( nRuntimeLimitSec > 0 ) - command += " " + to_string(nRuntimeLimitSec); + solverCall += " " + to_string(nRuntimeLimitSec); + command = solverCall; + if ( nRuntimeLimitSec > 0 ) + command = "timeout " + to_string(nRuntimeLimitSec) + " " + command; command += " > log.txt 2>&1"; LOG(1) << "UFAR external solver: launching command instead of PDR: " << command; #ifdef __wasm diff --git a/src/proof/abs/absGla.c b/src/proof/abs/absGla.c index 9f1a8a31e..72863fe73 100644 --- a/src/proof/abs/absGla.c +++ b/src/proof/abs/absGla.c @@ -1847,7 +1847,8 @@ int Gia_ManPerformGla( Gia_Man_t * pAig, Abs_Par_t * pPars ) } } finish: - Prf_ManStopP( &p->pSat->pPrf2 ); + if ( p->pSat ) + Prf_ManStopP( &p->pSat->pPrf2 ); // cancel old one if it is proving if ( iFrameTryToProve >= 0 ) Gia_GlaProveCancel( pPars->fVerbose ); @@ -1860,9 +1861,9 @@ finish: { Vec_IntFreeP( &pAig->vGateClasses ); pAig->vGateClasses = Ga2_ManAbsTranslate( p ); - if ( p->pPars->nTimeOut && Abc_Clock() >= p->pSat->nRuntimeLimit ) + if ( p->pSat && p->pPars->nTimeOut && Abc_Clock() >= p->pSat->nRuntimeLimit ) Abc_Print( 1, "GLA reached timeout %d sec in frame %d with a %d-stable abstraction. ", p->pPars->nTimeOut, p->pPars->iFrameProved+1, p->pPars->nFramesNoChange ); - else if ( pPars->nConfLimit && sat_solver2_nconflicts(p->pSat) >= pPars->nConfLimit ) + else if ( p->pSat && pPars->nConfLimit && sat_solver2_nconflicts(p->pSat) >= pPars->nConfLimit ) Abc_Print( 1, "GLA exceeded %d conflicts in frame %d with a %d-stable abstraction. ", pPars->nConfLimit, p->pPars->iFrameProved+1, p->pPars->nFramesNoChange ); else if ( pPars->nRatioMin2 && Vec_IntSize(p->vAbs) >= p->nMarked * pPars->nRatioMin2 / 100 ) Abc_Print( 1, "GLA found that the size of abstraction exceeds %d %% in frame %d during refinement. ", pPars->nRatioMin2, p->pPars->iFrameProved+1 ); @@ -1893,7 +1894,8 @@ finish: ABC_PRTP( "Runtime: Refinement ", p->timeCex, Abc_Clock() - clk ); ABC_PRTP( "Runtime: Other ", p->timeOther, Abc_Clock() - clk ); ABC_PRTP( "Runtime: TOTAL ", Abc_Clock() - clk, Abc_Clock() - clk ); - Ga2_ManReportMemory( p ); + if ( p->pSat ) + Ga2_ManReportMemory( p ); } // Ga2_ManDumpStats( p->pGia, p->pPars, p->pSat, p->pPars->iFrameProved, 0 ); Ga2_ManStop( p ); diff --git a/src/proof/cec/cec.h b/src/proof/cec/cec.h index e360bb99d..eed2cfaf9 100644 --- a/src/proof/cec/cec.h +++ b/src/proof/cec/cec.h @@ -167,6 +167,7 @@ struct Cec_ParCor_t_ // int fFirstStop; // stop on the first sat output int fUseSmartCnf; // use smart CNF computation int fStopWhenGone; // quit when PO is not a candidate constant + int fIncremental; // active-list/TFO-triggered reproof in main loop int fVerboseFlops; // verbose stats int fVeryVerbose; // verbose stats int fVerbose; // verbose stats diff --git a/src/proof/cec/cecCorr.c b/src/proof/cec/cecCorr.c index 0496b2e49..d5a091808 100644 --- a/src/proof/cec/cecCorr.c +++ b/src/proof/cec/cecCorr.c @@ -34,7 +34,10 @@ static inline int Cec_ParCorShouldStop( Cec_ParCor_t * pPars ) /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// -static void Gia_ManCorrSpecReduce_rec( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj, int f, int nPrefix ); +// Shared with cecCorrIncr.c (declared in cecInt.h). +extern void Gia_ManCorrSpecReduce_rec( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj, int f, int nPrefix ); +extern int Gia_ManCorrSpecReal( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj, int f, int nPrefix ); + //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// @@ -45,13 +48,13 @@ static void Gia_ManCorrSpecReduce_rec( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_ Synopsis [Computes the real value of the literal w/o spec reduction.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -static inline int Gia_ManCorrSpecReal( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj, int f, int nPrefix ) +int Gia_ManCorrSpecReal( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj, int f, int nPrefix ) { if ( Gia_ObjIsAnd(pObj) ) { @@ -762,6 +765,7 @@ void Cec_ManRefinedClassPrintStats( Gia_Man_t * p, Vec_Str_t * vStatus, int iIte Abc_Print( 1, "p =%6d d =%6d f =%6d ", nProve, nDispr, nFail ); Abc_Print( 1, "%c ", Gia_ObjIsConst( p, Gia_ObjFaninId0p(p, Gia_ManPo(p, 0)) ) ? '+' : '-' ); Abc_PrintTime( 1, "T", Time ); + fflush( stdout ); } int Cec_ManCountLits( Gia_Man_t * p ) { @@ -791,7 +795,7 @@ int Cec_ManCountLits( Gia_Man_t * p ) ***********************************************************************/ void Cec_ManLSCorrespondenceBmc( Gia_Man_t * pAig, Cec_ParCor_t * pPars, int nPrefs ) -{ +{ Cec_ParSim_t ParsSim, * pParsSim = &ParsSim; Cec_ParSat_t ParsSat, * pParsSat = &ParsSat; Vec_Str_t * vStatus; @@ -800,6 +804,7 @@ void Cec_ManLSCorrespondenceBmc( Gia_Man_t * pAig, Cec_ParCor_t * pPars, int nPr Cec_ManSim_t * pSim; Gia_Man_t * pSrm; int fChanges, RetValue, i; + Cec_IncrMgr_t * pBmcMgr = NULL; // prepare simulation manager Cec_ManSimSetDefaultParams( pParsSim ); pParsSim->nWords = pPars->nWords; @@ -812,20 +817,44 @@ void Cec_ManLSCorrespondenceBmc( Gia_Man_t * pAig, Cec_ParCor_t * pPars, int nPr Cec_ManSatSetDefaultParams( pParsSat ); pParsSat->nBTLimit = pPars->nBTLimit; pParsSat->fVerbose = pPars->fVerbose; + if ( pPars->fIncremental ) + { + pBmcMgr = Cec_IncrMgrAlloc( pAig, pPars->nFrames + nPrefs ); + Cec_IncrMgrSnapshotClasses( pBmcMgr ); + } fChanges = 1; for ( i = 0; fChanges && (!pPars->nLimitMax || i < pPars->nLimitMax); i++ ) { + int * pTfoMask = NULL; + int nReprSeeds = 0, nTotalPairs = 0, nActivePairs = 0, fConverged = 0; if ( Cec_ParCorShouldStop( pPars ) ) break; abctime clkBmc = Abc_Clock(); fChanges = 0; - pSrm = Gia_ManCorrSpecReduceInit( pAig, pPars->nFrames, nPrefs, !pPars->fLatchCorr, &vOutputs, pPars->fUseRings ); + // BMC SRM is non-ring (Gia_ManCorrSpecReduceInit ignores fRings); + // the incremental mask filters on pReprs-derived endpoints only. + if ( pBmcMgr && i > 0 ) + { + pTfoMask = Cec_IncrMgrDecideMask( pBmcMgr, 0, &fConverged, + &nReprSeeds, NULL, &nTotalPairs, &nActivePairs ); + if ( fConverged ) + break; + } + if ( pTfoMask ) + pSrm = Gia_ManCorrSpecReduceInit_Active( pAig, pPars->nFrames, nPrefs, !pPars->fLatchCorr, &vOutputs, pTfoMask ); + else + pSrm = Gia_ManCorrSpecReduceInit( pAig, pPars->nFrames, nPrefs, !pPars->fLatchCorr, &vOutputs, pPars->fUseRings ); + if ( pTfoMask && pPars->fVeryVerbose ) + Abc_Print( 1, " [bmc-incr i=%d repr=%d active=%d/%d POs=%d]\n", + i, nReprSeeds, nActivePairs, nTotalPairs, Gia_ManCoNum(pSrm) ); + if ( pBmcMgr ) + Cec_IncrMgrSnapshotClasses( pBmcMgr ); if ( Gia_ManPoNum(pSrm) == 0 ) { Gia_ManStop( pSrm ); Vec_IntFree( vOutputs ); break; - } + } pParsSat->nBTLimit *= 10; if ( pPars->fUseCSat ) vCexStore = Tas_ManSolveMiterNc( pSrm, pPars->nBTLimit, &vStatus, 0 ); @@ -848,6 +877,7 @@ void Cec_ManLSCorrespondenceBmc( Gia_Man_t * pAig, Cec_ParCor_t * pPars, int nPr if ( Cec_ParCorShouldStop( pPars ) ) break; } + Cec_IncrMgrFree( pBmcMgr ); Cec_ManSimStop( pSim ); } @@ -948,6 +978,9 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) abctime clkTotal = Abc_Clock(); abctime clkSat = 0, clkSim = 0, clkSrm = 0; abctime clk2, clk = Abc_Clock(); + Cec_IncrMgr_t * pMgr = NULL; // incremental manager (NULL when -i is off) + abctime clkIncr = 0; + int nIncrSkipped = 0, nIncrFallback = 0; if ( Gia_ManRegNum(pAig) == 0 ) { Abc_Print( 1, "Cec_ManLatchCorrespondence(): Not a sequential AIG.\n" ); @@ -994,27 +1027,69 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) if ( pPars->nStepsMax == 0 ) { Abc_Print( 1, "Stopped signal correspondence after BMC.\n" ); + fflush( stdout ); Cec_ManSimStop( pSim ); return 1; } + if ( pPars->fIncremental ) + { + pMgr = Cec_IncrMgrAlloc( pAig, pPars->nFrames ); + Cec_IncrMgrSnapshotClasses( pMgr ); + } // perform refinement of equivalence classes for ( r = 0; r < nIterMax; r++ ) - { + { if ( Cec_ParCorShouldStop( pPars ) ) { Cec_ManSimStop( pSim ); + Cec_IncrMgrFree( pMgr ); return 1; } if ( pPars->nStepsMax == r ) { Cec_ManSimStop( pSim ); + Cec_IncrMgrFree( pMgr ); Abc_Print( 1, "Stopped signal correspondence after %d refiment iterations.\n", r ); + fflush( stdout ); return 1; } clk = Abc_Clock(); - // perform speculative reduction + // perform speculative reduction (with optional active-list filter) clk2 = Abc_Clock(); - pSrm = Gia_ManCorrSpecReduce( pAig, pPars->nFrames, !pPars->fLatchCorr, &vOutputs, pPars->fUseRings ); + { + int * pTfoMask = NULL; + int nReprSeeds = 0, nNextChanges = 0, nTotalPairs = 0, nActivePairs = 0; + int fConverged = 0; + if ( pMgr && r > 0 ) + { + abctime clkI = Abc_Clock(); + pTfoMask = Cec_IncrMgrDecideMask( pMgr, pPars->fUseRings, &fConverged, + &nReprSeeds, &nNextChanges, + &nTotalPairs, &nActivePairs ); + clkIncr += Abc_Clock() - clkI; + if ( fConverged ) + { + clkSrm += Abc_Clock() - clk2; + break; + } + if ( pTfoMask == NULL ) + nIncrFallback++; + else + nIncrSkipped += nTotalPairs - nActivePairs; + } + if ( pTfoMask ) + pSrm = Gia_ManCorrSpecReduce_Active( pAig, pPars->nFrames, !pPars->fLatchCorr, &vOutputs, pPars->fUseRings, pTfoMask, pMgr ); + else + pSrm = Gia_ManCorrSpecReduce( pAig, pPars->nFrames, !pPars->fLatchCorr, &vOutputs, pPars->fUseRings ); + if ( pTfoMask && pPars->fVeryVerbose ) + Abc_Print( 1, " [incr r=%d repr=%d next=%d tfo=%d active=%d/%d POs=%d]\n", + r, nReprSeeds, nNextChanges, Vec_IntSize(pMgr->vTfoNodes), + nActivePairs, nTotalPairs, Gia_ManCoNum(pSrm) ); + // Snapshot AFTER SRM build: the active builder still reads the + // previous pNexts to recognise newly-created ring edges. + if ( pMgr ) + Cec_IncrMgrSnapshotClasses( pMgr ); + } assert( Gia_ManRegNum(pSrm) == 0 && Gia_ManPiNum(pSrm) == Gia_ManRegNum(pAig)+(pPars->nFrames+!pPars->fLatchCorr)*Gia_ManPiNum(pAig) ); clkSrm += Abc_Clock() - clk2; if ( Gia_ManCoNum(pSrm) == 0 ) @@ -1055,6 +1130,7 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) if ( Cec_ParCorShouldStop( pPars ) ) { Cec_ManSimStop( pSim ); + Cec_IncrMgrFree( pMgr ); return 1; } // quit if const is no longer there @@ -1062,7 +1138,9 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) { printf( "Iterative refinement is stopped after iteration %d\n", r ); printf( "because the property output is no longer a candidate constant.\n" ); + fflush( stdout ); Cec_ManSimStop( pSim ); + Cec_IncrMgrFree( pMgr ); return 0; } if ( pPars->nLimitMax ) @@ -1072,7 +1150,9 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) { printf( "Iterative refinement is stopped after iteration %d\n", r ); printf( "because refinement does not proceed quickly.\n" ); + fflush( stdout ); Cec_ManSimStop( pSim ); + Cec_IncrMgrFree( pMgr ); ABC_FREE( pAig->pReprs ); ABC_FREE( pAig->pNexts ); return 0; @@ -1100,10 +1180,17 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) ABC_PRTP( "Sat ", clkSat, clkTotal ); ABC_PRTP( "Sim ", clkSim, clkTotal ); ABC_PRTP( "Other", clkTotal-clkSat-clkSrm-clkSim, clkTotal ); + if ( pMgr ) + { + ABC_PRTP( "Incr ", clkIncr, clkTotal ); + Abc_Print( 1, "Incr: fallback rounds = %d, skipped candidate pairs = %d\n", nIncrFallback, nIncrSkipped ); + } Abc_PrintTime( 1, "TOTAL", clkTotal ); + fflush( stdout ); } + Cec_IncrMgrFree( pMgr ); return 1; -} +} /**Function************************************************************* @@ -1299,42 +1386,107 @@ Gia_Man_t * Cec_ManLSCorrespondence( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) SeeAlso [] ***********************************************************************/ -Vec_Wec_t * Gia_ManCreateRegSupps( Gia_Man_t * p, int fVerbose ) +static inline void Gia_ManStopFlopSuppAdd( int * pReg0, int * pReg1, int * pnRegs, int Reg ) { - abctime clk = Abc_Clock(); - Gia_Obj_t * pObj; int i, Id; - Vec_Wec_t * vSuppsR = Vec_WecStart( Gia_ManRegNum(p) ); - Vec_Wec_t * vSupps = Vec_WecStart( Gia_ManObjNum(p) ); - Gia_ManForEachRo( p, pObj, i ) - Vec_IntPush( Vec_WecEntry(vSupps, Gia_ObjId(p, pObj)), i ); - Gia_ManForEachAnd( p, pObj, Id ) - Vec_IntTwoMerge2( Vec_WecEntry(vSupps, Gia_ObjFaninId0(pObj, Id)), - Vec_WecEntry(vSupps, Gia_ObjFaninId1(pObj, Id)), - Vec_WecEntry(vSupps, Id) ); - Gia_ManForEachRi( p, pObj, i ) - Vec_IntAppend( Vec_WecEntry(vSuppsR, i), Vec_WecEntry(vSupps, Gia_ObjFaninId0p(p, pObj)) ); - Vec_WecFree( vSupps ); - if ( fVerbose ) - Abc_PrintTime( 1, "Support computation", Abc_Clock() - clk ); - return vSuppsR; + if ( *pnRegs == 3 ) + return; + if ( *pnRegs == 0 ) + { + *pReg0 = Reg; + *pnRegs = 1; + return; + } + if ( *pnRegs == 1 ) + { + if ( *pReg0 == Reg ) + return; + *pReg1 = Reg; + *pnRegs = 2; + return; + } + assert( *pnRegs == 2 ); + if ( *pReg0 == Reg || *pReg1 == Reg ) + return; + *pnRegs = 3; } Vec_Int_t * Gia_ManFindStopFlops( Gia_Man_t * p, int nFlopIncFreq, int fVerbose ) { - Vec_Int_t * vRes = NULL, * vTemp; int i, k, Spot, Temp, nItems = 0; - Vec_Wec_t * vSupps = Gia_ManCreateRegSupps( p, fVerbose ); + abctime clk = Abc_Clock(); + Gia_Obj_t * pObj; + Vec_Int_t * vRes = NULL; Vec_Int_t * vNexts = Vec_IntStartFull( Gia_ManRegNum(p) ); Vec_Int_t * vAvail = Vec_IntStart( Gia_ManRegNum(p) ); Vec_Int_t * vHeads = Vec_IntAlloc( 10 ); - Vec_WecForEachLevel( vSupps, vTemp, i ) { - if ( Vec_IntSize(vTemp) > 2 ) - continue; - if ( (Spot = Vec_IntFind(vTemp, i)) >= 0 ) - Vec_IntDrop( vTemp, Spot ); - if ( Vec_IntSize(vTemp) != 1 ) - continue; - Vec_IntWriteEntry( vNexts, i, Vec_IntEntry(vTemp, 0) ); - Vec_IntWriteEntry( vAvail, Vec_IntEntry(vTemp, 0), 1 ); + unsigned char * pSuppN = ABC_CALLOC( unsigned char, Gia_ManObjNum(p) ); + int * pSupp0 = ABC_ALLOC( int, Gia_ManObjNum(p) ); + int * pSupp1 = ABC_ALLOC( int, Gia_ManObjNum(p) ); + int i, k, Id, Fan0, Fan1, Count, Next, Spot, Temp, nItems = 0; + + // Track at most two distinct flop supports per node; value 3 means "many". + Gia_ManForEachRo( p, pObj, i ) + { + Id = Gia_ObjId( p, pObj ); + pSuppN[Id] = 1; + pSupp0[Id] = i; } + Gia_ManForEachAnd( p, pObj, Id ) + { + int Reg0 = -1, Reg1 = -1, nRegs = 0; + Fan0 = Gia_ObjFaninId0( pObj, Id ); + Fan1 = Gia_ObjFaninId1( pObj, Id ); + if ( pSuppN[Fan0] == 3 || pSuppN[Fan1] == 3 ) + { + pSuppN[Id] = 3; + continue; + } + if ( pSuppN[Fan0] > 0 ) + { + Gia_ManStopFlopSuppAdd( &Reg0, &Reg1, &nRegs, pSupp0[Fan0] ); + if ( pSuppN[Fan0] > 1 ) + Gia_ManStopFlopSuppAdd( &Reg0, &Reg1, &nRegs, pSupp1[Fan0] ); + } + if ( pSuppN[Fan1] > 0 ) + { + Gia_ManStopFlopSuppAdd( &Reg0, &Reg1, &nRegs, pSupp0[Fan1] ); + if ( pSuppN[Fan1] > 1 ) + Gia_ManStopFlopSuppAdd( &Reg0, &Reg1, &nRegs, pSupp1[Fan1] ); + } + pSuppN[Id] = nRegs; + if ( nRegs > 0 ) + pSupp0[Id] = Reg0; + if ( nRegs > 1 ) + pSupp1[Id] = Reg1; + } + if ( fVerbose ) + { + Abc_PrintTime( 1, "Support computation", Abc_Clock() - clk ); + fflush( stdout ); + } + + Gia_ManForEachRi( p, pObj, i ) + { + Id = Gia_ObjFaninId0p( p, pObj ); + Count = pSuppN[Id]; + Next = -1; + if ( Count == 1 ) + Next = pSupp0[Id] == i ? -1 : pSupp0[Id]; + else if ( Count == 2 ) + { + if ( pSupp0[Id] == i && pSupp1[Id] != i ) + Next = pSupp1[Id]; + else if ( pSupp1[Id] == i && pSupp0[Id] != i ) + Next = pSupp0[Id]; + } + if ( Next >= 0 ) + { + Vec_IntWriteEntry( vNexts, i, Next ); + Vec_IntWriteEntry( vAvail, Next, 1 ); + } + } + ABC_FREE( pSuppN ); + ABC_FREE( pSupp0 ); + ABC_FREE( pSupp1 ); + Vec_IntForEachEntry( vNexts, Spot, i ) if ( Spot >= 0 && Vec_IntEntry(vAvail, i) == 0 ) Vec_IntPush( vHeads, i ); @@ -1366,11 +1518,13 @@ Vec_Int_t * Gia_ManFindStopFlops( Gia_Man_t * p, int nFlopIncFreq, int fVerbose } } if ( fVerbose && vRes ) + { printf( "Detected %d sequence%s containing %d flops.\n", nItems, nItems > 1 ? "s":"", Vec_IntSize(vRes) ); + fflush( stdout ); + } Vec_IntFree( vNexts ); Vec_IntFree( vAvail ); Vec_IntFree( vHeads ); - Vec_WecFree( vSupps ); return vRes; } Gia_Man_t * Gia_ManDupStopsAdd( Gia_Man_t * p, Vec_Int_t * vStops ) diff --git a/src/proof/cec/cecCorrIncr.c b/src/proof/cec/cecCorrIncr.c new file mode 100644 index 000000000..fcc61c0b2 --- /dev/null +++ b/src/proof/cec/cecCorrIncr.c @@ -0,0 +1,674 @@ +/**CFile**************************************************************** + + FileName [cecCorrIncr.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Combinational equivalence checking.] + + Synopsis [Incremental active-list / TFO filter for &scorr.] + + Author [Xiran Zhao] + + Affiliation [University of Chinese Academy of Sciences] + + Date [Ver. 1.0. Started - May 2026.] + +***********************************************************************/ + +#include "cecInt.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Allocates the incremental active-list manager.] + + Description [The manager owns one snapshot of pReprs/pNexts plus the + TFO bookkeeping arrays. pAig must outlive the manager; the manager + never duplicates the AIG, only references it. If the host AIG does + not yet carry a static fanout, this routine builds it and remembers + to tear it down on Free.] + + SideEffects [Builds static fanout on pAig if not already present.] + + SeeAlso [] + +***********************************************************************/ +Cec_IncrMgr_t * Cec_IncrMgrAlloc( Gia_Man_t * pAig, int nFrames ) +{ + Cec_IncrMgr_t * p = ABC_CALLOC( Cec_IncrMgr_t, 1 ); + p->pAig = pAig; + p->nFrames = nFrames; + p->nObjs = Gia_ManObjNum(pAig); + p->vReprPrev = Vec_IntStartFull( p->nObjs ); + p->vNextPrev = Vec_IntStart( p->nObjs ); + p->vSeeds = Vec_IntAlloc( 64 ); + p->vTfoNodes = Vec_IntAlloc( 1024 ); + p->pTfoMark = ABC_CALLOC( int, p->nObjs ); + p->vBfsCur = Vec_IntAlloc( 1024 ); + p->vBfsNext = Vec_IntAlloc( 1024 ); + if ( pAig->vFanout == NULL ) + { + Gia_ManStaticFanoutStart( pAig ); + p->fOwnsFanout = 1; + } + return p; +} + +/**Function************************************************************* + + Synopsis [Frees the incremental manager.] + + Description [Releases all internal vectors and the TFO mark array. + If the manager built the static fanout on Alloc, it is also torn + down here. Safe to call with a NULL pointer.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cec_IncrMgrFree( Cec_IncrMgr_t * p ) +{ + if ( p == NULL ) return; + if ( p->fOwnsFanout ) + Gia_ManStaticFanoutStop( p->pAig ); + Vec_IntFree( p->vReprPrev ); + Vec_IntFree( p->vNextPrev ); + Vec_IntFree( p->vSeeds ); + Vec_IntFree( p->vTfoNodes ); + Vec_IntFree( p->vBfsCur ); + Vec_IntFree( p->vBfsNext ); + ABC_FREE( p->pTfoMark ); + ABC_FREE( p ); +} + +/**Function************************************************************* + + Synopsis [Snapshots the current equivalence-class state.] + + Description [Copies the per-node pReprs and pNexts arrays into the + manager so the next iteration can diff against the class state whose + pairs were just emitted into the SRM. Should be called after SRM + construction and before SAT/sim refinement: the snapshot then reflects + exactly the pairs the SAT solver was asked to prove. O(N).] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Cec_IncrMgrSnapshotClasses( Cec_IncrMgr_t * p ) +{ + Gia_Man_t * pAig = p->pAig; + int i; + assert( pAig->pReprs != NULL ); + for ( i = 0; i < p->nObjs; i++ ) + { + Vec_IntWriteEntry( p->vReprPrev, i, Gia_ObjRepr(pAig, i) ); + Vec_IntWriteEntry( p->vNextPrev, i, pAig->pNexts ? Gia_ObjNext(pAig, i) : 0 ); + } +} + +/**Function************************************************************* + + Synopsis [Computes the seed set for the next TFO BFS.] + + Description [Returns the number of nodes whose representative changed + since the last snapshot; the seeds themselves are stored in vSeeds and + consumed by Cec_IncrMgrComputeTfo. Does not update the snapshot -- + the caller decides when to snapshot. pNexts changes are intentionally + excluded here: a ring-link rewrite is an edge-local event that creates + a new ring edge to reprove, not a new fanout cone, so it is handled by + Cec_IncrMgrRingEdgeChanged at SRM emission time.] + + SideEffects [] + + SeeAlso [Cec_IncrMgrComputeTfo Cec_IncrMgrRingEdgeChanged] + +***********************************************************************/ +int Cec_IncrMgrComputeSeeds( Cec_IncrMgr_t * p ) +{ + Gia_Man_t * pAig = p->pAig; + int i, reprNew, reprOld; + Vec_IntClear( p->vSeeds ); + for ( i = 1; i < p->nObjs; i++ ) + { + reprNew = Gia_ObjRepr( pAig, i ); + reprOld = Vec_IntEntry( p->vReprPrev, i ); + if ( reprNew != reprOld ) + Vec_IntPush( p->vSeeds, i ); + } + return Vec_IntSize( p->vSeeds ); +} + +/**Function************************************************************* + + Synopsis [Counts nodes whose ring-list successor changed.] + + Description [Used only for convergence and fallback decisions. These + nodes are NOT TFO seeds, because a pNexts-only change creates a new + ring edge (proved edge-locally by the active SRM builder) rather than + a new fanout cone to re-prove. Returns 0 when pNexts is unallocated, + i.e. when ring mode is off.] + + SideEffects [] + + SeeAlso [Cec_IncrMgrComputeSeeds] + +***********************************************************************/ +int Cec_IncrMgrCountNextChanges( Cec_IncrMgr_t * p ) +{ + Gia_Man_t * pAig = p->pAig; + int i, nChanges = 0; + if ( pAig->pNexts == NULL ) + return 0; + for ( i = 1; i < p->nObjs; i++ ) + nChanges += Gia_ObjNext( pAig, i ) != Vec_IntEntry( p->vNextPrev, i ); + return nChanges; +} + +/**Function************************************************************* + + Synopsis [Detects whether a ring edge is new since the last snapshot.] + + Description [Ring classes store list edges explicitly in pNexts, but + the SRM also proves the implicit closing edge tail -> head. For an + explicit edge, the edge is unchanged iff the predecessor's pNexts slot + still names the same successor. For the closing edge there is no + pNexts slot to compare, so we reconstruct whether the same tail/head + pair already existed in the previous snapshot: the tail must have been + pointing to the head (closing the ring) and the head must still have + been a class root. Returns 1 to mean "must be re-proved". Passing a + NULL manager or a non-ring AIG returns 0 (no edge work needed).] + + SideEffects [] + + SeeAlso [Cec_IncrMgrCountActivePairs] + +***********************************************************************/ +int Cec_IncrMgrRingEdgeChanged( Cec_IncrMgr_t * p, int iPrev, int iObj ) +{ + Gia_Man_t * pAig; + int iNextCur, iNextOld; + if ( p == NULL ) + return 0; + pAig = p->pAig; + if ( pAig->pNexts == NULL ) + return 0; + iNextCur = Gia_ObjNext( pAig, iPrev ); + iNextOld = Vec_IntEntry( p->vNextPrev, iPrev ); + if ( iNextCur == iObj ) + return iNextOld != iObj; + if ( iNextCur > 0 ) + return 1; // conservative: should not happen for callers below + // Closing edge: prove if the previous snapshot did not already contain + // exactly this tail/head pair as a ring's closing edge. + return iNextOld > 0 || + Vec_IntEntry( p->vReprPrev, iPrev ) != iObj || + Vec_IntEntry( p->vReprPrev, iObj ) != GIA_VOID || + Vec_IntEntry( p->vNextPrev, iObj ) <= 0; +} + +/**Function************************************************************* + + Synopsis [Counts total and active candidate pairs before SRM build.] + + Description [Mirrors the PO-emission loops in the active SRM builders + but stops before constructing the unrolled network: it walks every + candidate pair the SRM would emit and tallies how many would survive + the active filter (pTfoMark plus the ring-edge override). The count + is approximate because SRM construction can still simplify a pair + away after the literal it represents collapses; it is used only to + decide whether the active filter saves enough work to be worth the + bookkeeping (the main loop falls back to the full SRM above ~70% + active pairs). When pTfoMark is NULL every pair is counted active.] + + SideEffects [] + + SeeAlso [Gia_ManCorrSpecReduce_Active] + +***********************************************************************/ +void Cec_IncrMgrCountActivePairs( Cec_IncrMgr_t * p, int fRings, int * pTfoMark, + int * pnTotal, int * pnActive ) +{ + Gia_Man_t * pAig = p->pAig; + Gia_Obj_t * pObj, * pRepr; + int i, iPrev, iObj; + *pnTotal = *pnActive = 0; + assert( pAig->pReprs != NULL ); + if ( fRings ) + { + Gia_ManForEachObj1( pAig, pObj, i ) + { + if ( Gia_ObjIsConst( pAig, i ) ) + { + (*pnTotal)++; + (*pnActive) += pTfoMark == NULL || pTfoMark[i]; + } + else if ( Gia_ObjIsHead( pAig, i ) ) + { + iPrev = i; + Gia_ClassForEachObj1( pAig, i, iObj ) + { + (*pnTotal)++; + (*pnActive) += pTfoMark == NULL || pTfoMark[iPrev] || pTfoMark[iObj] || + Cec_IncrMgrRingEdgeChanged( p, iPrev, iObj ); + iPrev = iObj; + } + iObj = i; // closing edge tail -> head + (*pnTotal)++; + (*pnActive) += pTfoMark == NULL || pTfoMark[iPrev] || pTfoMark[iObj] || + Cec_IncrMgrRingEdgeChanged( p, iPrev, iObj ); + } + } + } + else + { + Gia_ManForEachObj1( pAig, pObj, i ) + { + int idR; + pRepr = Gia_ObjReprObj( pAig, Gia_ObjId(pAig,pObj) ); + if ( pRepr == NULL ) + continue; + idR = Gia_ObjId( pAig, pRepr ); + (*pnTotal)++; + (*pnActive) += pTfoMark == NULL || pTfoMark[i] || pTfoMark[idR]; + } + } +} + +/**Function************************************************************* + + Synopsis [Forward TFO BFS from seeds across nFrames unrollings.] + + Description [Marks pTfoMark[id]=1 for every AIG node reachable from + any seed within nFrames combinational+sequential steps. Each frame + performs a combinational fanout BFS; RI fanouts cross to the next + frame by following Gia_ObjRiToRo to the corresponding register output. + After nFrames cross-frame jumps the search stops, since pairs deeper + than that cannot depend on the seeds within an nFrames-deep SRM. + + RI nodes themselves are intentionally not marked: SRM emission is + keyed on AIG candidate nodes (ANDs and CIs) and never on COs, so + marking RIs would only inflate the active set without enabling any + additional pair. + + Mark clearing is amortised: vTfoNodes records every id touched in + the previous round and is iterated to zero only those entries, so + the routine never sweeps the full N-sized array. Cost per call is + O(|TFO_k| * avg_fanout).] + + SideEffects [] + + SeeAlso [Cec_IncrMgrComputeSeeds] + +***********************************************************************/ +void Cec_IncrMgrComputeTfo( Cec_IncrMgr_t * p ) +{ + Gia_Man_t * pAig = p->pAig; + int * pMark = p->pTfoMark; + int f, i, k, Id, FanId, RoId; + + Vec_IntForEachEntry( p->vTfoNodes, Id, i ) + pMark[Id] = 0; + Vec_IntClear( p->vTfoNodes ); + Vec_IntClear( p->vBfsCur ); + Vec_IntClear( p->vBfsNext ); + + Vec_IntForEachEntry( p->vSeeds, Id, i ) + { + if ( !pMark[Id] ) + { + pMark[Id] = 1; + Vec_IntPush( p->vTfoNodes, Id ); + Vec_IntPush( p->vBfsCur, Id ); + } + } + + for ( f = 0; f <= p->nFrames; f++ ) + { + int head = 0; + while ( head < Vec_IntSize(p->vBfsCur) ) + { + Gia_Obj_t * pFan; + Id = Vec_IntEntry( p->vBfsCur, head++ ); + int nFan = Gia_ObjFanoutNumId( pAig, Id ); + for ( k = 0; k < nFan; k++ ) + { + FanId = Gia_ObjFanoutId( pAig, Id, k ); + pFan = Gia_ManObj( pAig, FanId ); + if ( Gia_ObjIsRi(pAig, pFan) ) + { + if ( f < p->nFrames ) + { + RoId = Gia_ObjRiToRoId( pAig, FanId ); + if ( !pMark[RoId] ) + { + pMark[RoId] = 1; + Vec_IntPush( p->vTfoNodes, RoId ); + Vec_IntPush( p->vBfsNext, RoId ); + } + } + } + else if ( Gia_ObjIsCo(pFan) ) + { + // PO: not a candidate, skip + } + else + { + if ( !pMark[FanId] ) + { + pMark[FanId] = 1; + Vec_IntPush( p->vTfoNodes, FanId ); + Vec_IntPush( p->vBfsCur, FanId ); + } + } + } + } + Vec_IntClear( p->vBfsCur ); + Vec_IntAppend( p->vBfsCur, p->vBfsNext ); + Vec_IntClear( p->vBfsNext ); + if ( Vec_IntSize(p->vBfsCur) == 0 ) + break; + } +} + +/**Function************************************************************* + + Synopsis [Active-filter variant of Gia_ManCorrSpecReduce.] + + Description [Identical to Gia_ManCorrSpecReduce in its SRM topology + and speculative reduction; the only difference is the PO emission + filter. A candidate pair (a, b) is emitted iff pTfoMark[a] is set + or pTfoMark[b] is set, i.e. at least one endpoint lies in the TFO of + a recently-changed representative. In ring mode, a ring edge that is + new or rewired since the last snapshot (Cec_IncrMgrRingEdgeChanged) + is also emitted even if neither endpoint is in the TFO -- the edge + has no prior UNSAT result to reuse and must be reproved on its own. + + Walking the full ring is required (rather than skipping unmarked + members) so iPrev stays aligned with the live class order; the active + filter only suppresses the resulting PO when the edge is provably + not new and neither endpoint is reachable from a seed. Passing + pTfoMark == NULL falls back to the unfiltered baseline behaviour.] + + SideEffects [] + + SeeAlso [Gia_ManCorrSpecReduce] + +***********************************************************************/ +Gia_Man_t * Gia_ManCorrSpecReduce_Active( Gia_Man_t * p, int nFrames, int fScorr, + Vec_Int_t ** pvOutputs, int fRings, + int * pTfoMark, Cec_IncrMgr_t * pIncr ) +{ + Gia_Man_t * pNew, * pTemp; + Gia_Obj_t * pObj, * pRepr; + Vec_Int_t * vXorLits; + int f, i, iPrev, iObj, iPrevNew, iObjNew; + assert( nFrames > 0 ); + assert( Gia_ManRegNum(p) > 0 ); + assert( p->pReprs != NULL ); + Vec_IntFill( &p->vCopies, (nFrames+fScorr)*Gia_ManObjNum(p), -1 ); + Gia_ManSetPhase( p ); + pNew = Gia_ManStart( nFrames * Gia_ManObjNum(p) ); + pNew->pName = Abc_UtilStrsav( p->pName ); + pNew->pSpec = Abc_UtilStrsav( p->pSpec ); + Gia_ManHashAlloc( pNew ); + Gia_ObjSetCopyF( p, 0, Gia_ManConst0(p), 0 ); + Gia_ManForEachRo( p, pObj, i ) + Gia_ObjSetCopyF( p, 0, pObj, Gia_ManAppendCi(pNew) ); + Gia_ManForEachRo( p, pObj, i ) + if ( (pRepr = Gia_ObjReprObj(p, Gia_ObjId(p, pObj))) ) + Gia_ObjSetCopyF( p, 0, pObj, Gia_ObjCopyF(p, 0, pRepr) ); + for ( f = 0; f < nFrames+fScorr; f++ ) + { + Gia_ObjSetCopyF( p, f, Gia_ManConst0(p), 0 ); + Gia_ManForEachPi( p, pObj, i ) + Gia_ObjSetCopyF( p, f, pObj, Gia_ManAppendCi(pNew) ); + } + *pvOutputs = Vec_IntAlloc( 1000 ); + vXorLits = Vec_IntAlloc( 1000 ); + if ( fRings ) + { + Gia_ManForEachObj1( p, pObj, i ) + { + if ( Gia_ObjIsConst( p, i ) ) + { + if ( pTfoMark && !pTfoMark[i] ) + continue; + iObjNew = Gia_ManCorrSpecReal( pNew, p, pObj, nFrames, 0 ); + iObjNew = Abc_LitNotCond( iObjNew, Gia_ObjPhase(pObj) ); + if ( iObjNew != 0 ) + { + Vec_IntPush( *pvOutputs, 0 ); + Vec_IntPush( *pvOutputs, i ); + Vec_IntPush( vXorLits, iObjNew ); + } + } + else if ( Gia_ObjIsHead( p, i ) ) + { + // Walk every ring edge so iPrev stays aligned with the class + // order; emit only when an endpoint is in TFO or the edge is + // new/rewired since the last snapshot. + iPrev = i; + Gia_ClassForEachObj1( p, i, iObj ) + { + int fEmit = (pTfoMark == NULL) || pTfoMark[iPrev] || pTfoMark[iObj] || + Cec_IncrMgrRingEdgeChanged( pIncr, iPrev, iObj ); + if ( fEmit ) + { + iPrevNew = Gia_ManCorrSpecReal( pNew, p, Gia_ManObj(p, iPrev), nFrames, 0 ); + iObjNew = Gia_ManCorrSpecReal( pNew, p, Gia_ManObj(p, iObj), nFrames, 0 ); + iPrevNew = Abc_LitNotCond( iPrevNew, Gia_ObjPhase(pObj) ^ Gia_ObjPhase(Gia_ManObj(p, iPrev)) ); + iObjNew = Abc_LitNotCond( iObjNew, Gia_ObjPhase(pObj) ^ Gia_ObjPhase(Gia_ManObj(p, iObj)) ); + if ( iPrevNew != iObjNew && iPrevNew != 0 && iObjNew != 1 ) + { + Vec_IntPush( *pvOutputs, iPrev ); + Vec_IntPush( *pvOutputs, iObj ); + Vec_IntPush( vXorLits, Gia_ManHashAnd(pNew, iPrevNew, Abc_LitNot(iObjNew)) ); + } + } + iPrev = iObj; + } + // Closing edge tail -> head + iObj = i; + { + int fEmit = (pTfoMark == NULL) || pTfoMark[iPrev] || pTfoMark[iObj] || + Cec_IncrMgrRingEdgeChanged( pIncr, iPrev, iObj ); + if ( fEmit ) + { + iPrevNew = Gia_ManCorrSpecReal( pNew, p, Gia_ManObj(p, iPrev), nFrames, 0 ); + iObjNew = Gia_ManCorrSpecReal( pNew, p, Gia_ManObj(p, iObj), nFrames, 0 ); + iPrevNew = Abc_LitNotCond( iPrevNew, Gia_ObjPhase(pObj) ^ Gia_ObjPhase(Gia_ManObj(p, iPrev)) ); + iObjNew = Abc_LitNotCond( iObjNew, Gia_ObjPhase(pObj) ^ Gia_ObjPhase(Gia_ManObj(p, iObj)) ); + if ( iPrevNew != iObjNew && iPrevNew != 0 && iObjNew != 1 ) + { + Vec_IntPush( *pvOutputs, iPrev ); + Vec_IntPush( *pvOutputs, iObj ); + Vec_IntPush( vXorLits, Gia_ManHashAnd(pNew, iPrevNew, Abc_LitNot(iObjNew)) ); + } + } + } + } + } + } + else + { + Gia_ManForEachObj1( p, pObj, i ) + { + pRepr = Gia_ObjReprObj( p, Gia_ObjId(p,pObj) ); + if ( pRepr == NULL ) + continue; + if ( pTfoMark ) + { + int idR = Gia_ObjId(p, pRepr); + if ( !pTfoMark[i] && !pTfoMark[idR] ) + continue; + } + iPrevNew = Gia_ObjIsConst(p, i)? 0 : Gia_ManCorrSpecReal( pNew, p, pRepr, nFrames, 0 ); + iObjNew = Gia_ManCorrSpecReal( pNew, p, pObj, nFrames, 0 ); + iObjNew = Abc_LitNotCond( iObjNew, Gia_ObjPhase(pRepr) ^ Gia_ObjPhase(pObj) ); + if ( iPrevNew != iObjNew ) + { + Vec_IntPush( *pvOutputs, Gia_ObjId(p, pRepr) ); + Vec_IntPush( *pvOutputs, Gia_ObjId(p, pObj) ); + Vec_IntPush( vXorLits, Gia_ManHashXor(pNew, iPrevNew, iObjNew) ); + } + } + } + Vec_IntForEachEntry( vXorLits, iObjNew, i ) + Gia_ManAppendCo( pNew, iObjNew ); + Vec_IntFree( vXorLits ); + Gia_ManHashStop( pNew ); + Vec_IntErase( &p->vCopies ); + pNew = Gia_ManCleanup( pTemp = pNew ); + Gia_ManStop( pTemp ); + return pNew; +} + +/**Function************************************************************* + + Synopsis [Active-filter variant of Gia_ManCorrSpecReduceInit (BMC SRM).] + + Description [Mirrors Gia_ManCorrSpecReduceInit but emits a candidate + PO (pRepr, pObj) only when at least one of the two endpoints lies in + pTfoMark. The baseline BMC SRM accepts an fRings flag for symmetry + with the inductive builder but never inspects it -- its topology is + always (head, member) pairs derived from pReprs alone, with no ring + edges to close. Therefore this active variant only needs pReprs- + driven seeds: pNexts changes cannot affect this SRM and there is no + closing edge to reprove. Passing pTfoMark == NULL falls back to the + unfiltered baseline behaviour.] + + SideEffects [] + + SeeAlso [Gia_ManCorrSpecReduceInit] + +***********************************************************************/ +Gia_Man_t * Gia_ManCorrSpecReduceInit_Active( Gia_Man_t * p, int nFrames, int nPrefix, int fScorr, + Vec_Int_t ** pvOutputs, int * pTfoMark ) +{ + Gia_Man_t * pNew, * pTemp; + Gia_Obj_t * pObj, * pRepr; + Vec_Int_t * vXorLits; + int f, i, iPrevNew, iObjNew; + assert( (!fScorr && nFrames > 1) || (fScorr && nFrames > 0) || nPrefix ); + assert( Gia_ManRegNum(p) > 0 ); + assert( p->pReprs != NULL ); + Vec_IntFill( &p->vCopies, (nFrames+nPrefix+fScorr)*Gia_ManObjNum(p), -1 ); + Gia_ManSetPhase( p ); + pNew = Gia_ManStart( (nFrames+nPrefix) * Gia_ManObjNum(p) ); + pNew->pName = Abc_UtilStrsav( p->pName ); + pNew->pSpec = Abc_UtilStrsav( p->pSpec ); + Gia_ManHashAlloc( pNew ); + Gia_ManForEachRo( p, pObj, i ) + { + Gia_ManAppendCi(pNew); + Gia_ObjSetCopyF( p, 0, pObj, 0 ); + } + for ( f = 0; f < nFrames+nPrefix+fScorr; f++ ) + { + Gia_ObjSetCopyF( p, f, Gia_ManConst0(p), 0 ); + Gia_ManForEachPi( p, pObj, i ) + Gia_ObjSetCopyF( p, f, pObj, Gia_ManAppendCi(pNew) ); + } + *pvOutputs = Vec_IntAlloc( 1000 ); + vXorLits = Vec_IntAlloc( 1000 ); + for ( f = nPrefix; f < nFrames+nPrefix; f++ ) + { + Gia_ManForEachObj1( p, pObj, i ) + { + pRepr = Gia_ObjReprObj( p, Gia_ObjId(p,pObj) ); + if ( pRepr == NULL ) + continue; + if ( pTfoMark ) + { + int idR = Gia_ObjId(p, pRepr); + if ( !pTfoMark[i] && !pTfoMark[idR] ) + continue; + } + iPrevNew = Gia_ObjIsConst(p, i)? 0 : Gia_ManCorrSpecReal( pNew, p, pRepr, f, nPrefix ); + iObjNew = Gia_ManCorrSpecReal( pNew, p, pObj, f, nPrefix ); + iObjNew = Abc_LitNotCond( iObjNew, Gia_ObjPhase(pRepr) ^ Gia_ObjPhase(pObj) ); + if ( iPrevNew != iObjNew ) + { + Vec_IntPush( *pvOutputs, Gia_ObjId(p, pRepr) ); + Vec_IntPush( *pvOutputs, Gia_ObjId(p, pObj) ); + Vec_IntPush( vXorLits, Gia_ManHashXor(pNew, iPrevNew, iObjNew) ); + } + } + } + Vec_IntForEachEntry( vXorLits, iObjNew, i ) + Gia_ManAppendCo( pNew, iObjNew ); + Vec_IntFree( vXorLits ); + Gia_ManHashStop( pNew ); + Vec_IntErase( &p->vCopies ); + pNew = Gia_ManCleanup( pTemp = pNew ); + Gia_ManStop( pTemp ); + return pNew; +} + +/**Function************************************************************* + + Synopsis [One-shot incremental decision for the refinement loop.] + + Description [Computes seeds, runs the TFO BFS, counts active candidate + pairs, and applies the fallback heuristic. Returns the TFO mask to + pass to the active SRM builder, or NULL when either (a) classes have + converged since the last snapshot (in which case *pfConverged is set + to 1 and the caller should break the refinement loop), or (b) the + active-pair ratio is high enough that the full SRM is cheaper. The + out parameters pnReprSeeds / pnNextChanges / pnTotalPairs / + pnActivePairs are filled when non-NULL and are useful for verbose + printing and progress counters. fUseRings tells the helper whether + to track pNexts changes; the BMC SRM is non-ring and passes 0.] + + SideEffects [] + + SeeAlso [Cec_IncrMgrComputeSeeds Cec_IncrMgrComputeTfo + Cec_IncrMgrCountActivePairs] + +***********************************************************************/ +int * Cec_IncrMgrDecideMask( Cec_IncrMgr_t * p, int fUseRings, int * pfConverged, + int * pnReprSeeds, int * pnNextChanges, + int * pnTotalPairs, int * pnActivePairs ) +{ + int nReprSeeds, nNextChanges = 0, nTotalPairs = 0, nActivePairs = 0; + *pfConverged = 0; + nReprSeeds = Cec_IncrMgrComputeSeeds( p ); + if ( fUseRings ) + nNextChanges = Cec_IncrMgrCountNextChanges( p ); + if ( pnReprSeeds ) *pnReprSeeds = nReprSeeds; + if ( pnNextChanges ) *pnNextChanges = nNextChanges; + if ( nReprSeeds == 0 && nNextChanges == 0 ) + { + *pfConverged = 1; + return NULL; + } + Cec_IncrMgrComputeTfo( p ); + Cec_IncrMgrCountActivePairs( p, fUseRings, p->pTfoMark, &nTotalPairs, &nActivePairs ); + if ( pnTotalPairs ) *pnTotalPairs = nTotalPairs; + if ( pnActivePairs ) *pnActivePairs = nActivePairs; + if ( nActivePairs == 0 ) + { + *pfConverged = 1; + return NULL; + } + // Above ~70% active pairs, the mask plus emission filter costs more + // than just rebuilding the full SRM. Return NULL to signal fallback. + if ( nTotalPairs > 0 && (ABC_INT64_T)10 * nActivePairs > (ABC_INT64_T)7 * nTotalPairs ) + return NULL; + return p->pTfoMark; +} + +ABC_NAMESPACE_IMPL_END + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// diff --git a/src/proof/cec/cecInt.h b/src/proof/cec/cecInt.h index f78e5f25f..f73256567 100644 --- a/src/proof/cec/cecInt.h +++ b/src/proof/cec/cecInt.h @@ -149,7 +149,7 @@ struct Cec_ManFra_t_ { // parameters Gia_Man_t * pAig; // the AIG to be used for simulation - Cec_ParFra_t * pPars; // SAT sweeping parameters + Cec_ParFra_t * pPars; // SAT sweeping parameters // simulation patterns Vec_Int_t * vXorNodes; // nodes used in speculative reduction int nAllProved; // total number of proved nodes @@ -165,6 +165,23 @@ struct Cec_ManFra_t_ abctime timeTotal; // total runtime }; +// incremental active-list manager for &scorr -i +typedef struct Cec_IncrMgr_t_ Cec_IncrMgr_t; +struct Cec_IncrMgr_t_ +{ + Gia_Man_t * pAig; // host AIG (immutable across iterations) + int nFrames; // unrolling depth used by the SRM builder + int nObjs; // cached Gia_ManObjNum(pAig) + Vec_Int_t * vReprPrev; // snapshot of pReprs from previous round + Vec_Int_t * vNextPrev; // snapshot of pNexts from previous round + Vec_Int_t * vSeeds; // nodes whose pReprs changed since snapshot + Vec_Int_t * vTfoNodes; // ids currently in TFO (for fast clearing) + int * pTfoMark; // dense mark array, size = nObjs + Vec_Int_t * vBfsCur; // BFS frontier for current frame + Vec_Int_t * vBfsNext; // BFS frontier carried to next frame + int fOwnsFanout; // 1 if we built static fanout (must free) +}; + //////////////////////////////////////////////////////////////////////// /// MACRO DEFINITIONS /// //////////////////////////////////////////////////////////////////////// @@ -175,6 +192,20 @@ struct Cec_ManFra_t_ /*=== cecCorr.c ============================================================*/ extern void Cec_ManRefinedClassPrintStats( Gia_Man_t * p, Vec_Str_t * vStatus, int iIter, abctime Time ); +extern int Gia_ManCorrSpecReal( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj, int f, int nPrefix ); +extern void Gia_ManCorrSpecReduce_rec( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj, int f, int nPrefix ); +/*=== cecCorrIncr.c ============================================================*/ +extern Cec_IncrMgr_t * Cec_IncrMgrAlloc( Gia_Man_t * pAig, int nFrames ); +extern void Cec_IncrMgrFree( Cec_IncrMgr_t * p ); +extern void Cec_IncrMgrSnapshotClasses( Cec_IncrMgr_t * p ); +extern int Cec_IncrMgrComputeSeeds( Cec_IncrMgr_t * p ); +extern int Cec_IncrMgrCountNextChanges( Cec_IncrMgr_t * p ); +extern int Cec_IncrMgrRingEdgeChanged( Cec_IncrMgr_t * p, int iPrev, int iObj ); +extern void Cec_IncrMgrCountActivePairs( Cec_IncrMgr_t * p, int fRings, int * pTfoMark, int * pnTotal, int * pnActive ); +extern void Cec_IncrMgrComputeTfo( Cec_IncrMgr_t * p ); +extern Gia_Man_t * Gia_ManCorrSpecReduce_Active( Gia_Man_t * p, int nFrames, int fScorr, Vec_Int_t ** pvOutputs, int fRings, int * pTfoMark, Cec_IncrMgr_t * pIncr ); +extern Gia_Man_t * Gia_ManCorrSpecReduceInit_Active( Gia_Man_t * p, int nFrames, int nPrefix, int fScorr, Vec_Int_t ** pvOutputs, int * pTfoMark ); +extern int * Cec_IncrMgrDecideMask( Cec_IncrMgr_t * p, int fUseRings, int * pfConverged, int * pnReprSeeds, int * pnNextChanges, int * pnTotalPairs, int * pnActivePairs ); /*=== cecClass.c ============================================================*/ extern int Cec_ManSimClassRemoveOne( Cec_ManSim_t * p, int i ); extern int Cec_ManSimClassesPrepare( Cec_ManSim_t * p, int LevelMax ); diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index b309f1a12..94eafa479 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -62,16 +62,16 @@ static int Cec_SProveCallback( void * pUser, int fSolved, unsigned Result ); static Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare, struct Cec_ScorrStop_t_ * pStopOut ); static Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare, struct Cec_ScorrStop_t_ * pStopOut ); #ifdef ABC_USE_PTHREADS -static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare, int * pEngines, int StageId, int NetId, struct Cec_SproveTrace_t_ * pTrace ); +static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, const char * pUfarArgs, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare, int * pEngines, int StageId, int NetId, struct Cec_SproveTrace_t_ * pTrace ); static void Cec_GiaStopThreads( Par_ThData_t * ThData, pthread_t * WorkerThread, int nWorkers ); #endif static int Cec_GiaWaitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int RetValue, int * pRetEngine ); -extern int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId ); +extern int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId, const char * pArgs ); #ifndef ABC_USE_PTHREADS -int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile ) { return -1; } +int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile, char * pUfarArgs ) { return -1; } int Cec_GiaReplayReadParams( char * pFileName, int * pnProcs, int * pnTimeOut, int * pnTimeOut2, int * pnTimeOut3, int * pfUseUif ) { return 0; } int Cec_GiaReplayTest( Gia_Man_t * p, Wlc_Ntk_t * pWlc, char * pFileName, int fVerbose, int fVeryVerbose, int fSilent ) { return -1; } @@ -106,6 +106,7 @@ typedef struct Par_ThData_t_ int fVerbose; int nTimeOutU; Wlc_Ntk_t * pWlc; + const char * pUfarArgs; int WorkerId; int StageId; int NetId; @@ -154,6 +155,9 @@ struct Cec_SprovePlan_t_ int nTimeOut2; int nTimeOut3; int fUseUif; + int fPersistentUif; + int nTimeOutUif; + char * pUfarArgs; int nStages; Cec_SproveStage_t Stages[SPROVE_STAGE_MAX]; }; @@ -307,13 +311,41 @@ static int Cec_SproveParseEngineName( const char * pName ) return i; return -1; } -static void Cec_SproveDeriveEngineList( int nProcs, int fUseUif, int * pEngines, int * pnEngines ) +static int Cec_SprovePlanTimeoutTotal( Cec_SprovePlan_t * pPlan ) { - int i, nEngines = nProcs + (fUseUif ? 1 : 0); + int i, Total = 0; + for ( i = 0; i < pPlan->nStages; i++ ) + { + Cec_SproveStage_t * pStage = &pPlan->Stages[i]; + int RoundTime = pStage->fHasRound ? pStage->RoundTimeout : 0; + int ReduceTime = pStage->fHasReduce ? pStage->ReduceTimeout : 0; + Total += Abc_MaxInt( RoundTime, ReduceTime ); + } + return Total; +} +static void Cec_SproveDeriveEngineList( int nProcs, int fUseUif, int fPersistentUif, int * pEngines, int * pnEngines ) +{ + int i, nEngines = nProcs + ((fUseUif && !fPersistentUif) ? 1 : 0); assert( nEngines >= 1 && nEngines <= PAR_THR_MAX ); + if ( fUseUif && nProcs == 6 ) + { + if ( fPersistentUif ) + { + int UifEngines[6] = { 0, 1, 2, 3, 4, PAR_ENGINE_GLA }; + memcpy( pEngines, UifEngines, sizeof(UifEngines) ); + *pnEngines = 6; + } + else + { + int UifEngines[7] = { 0, 1, 2, 3, 4, PAR_ENGINE_GLA, PAR_ENGINE_UFAR }; + memcpy( pEngines, UifEngines, sizeof(UifEngines) ); + *pnEngines = 7; + } + return; + } for ( i = 0; i < nEngines; i++ ) { - if ( fUseUif && i == nEngines - 1 ) + if ( fUseUif && !fPersistentUif && i == nEngines - 1 ) pEngines[i] = PAR_ENGINE_UFAR; else if ( !fUseUif && nEngines == 6 && i == 5 ) pEngines[i] = PAR_ENGINE_GLA; @@ -322,7 +354,25 @@ static void Cec_SproveDeriveEngineList( int nProcs, int fUseUif, int * pEngines, } *pnEngines = nEngines; } -static void Cec_SprovePlanDefault( Cec_SprovePlan_t * pPlan, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif ) +static void Cec_SproveTrimLineEnd( char * pLine ) +{ + int nSize = strlen( pLine ); + while ( nSize > 0 && (pLine[nSize - 1] == '\n' || pLine[nSize - 1] == '\r') ) + pLine[--nSize] = 0; +} +static void Cec_SprovePlanSetUfarArgs( Cec_SprovePlan_t * pPlan, const char * pUfarArgs ) +{ + ABC_FREE( pPlan->pUfarArgs ); + pPlan->pUfarArgs = NULL; + if ( pUfarArgs && pUfarArgs[0] ) + pPlan->pUfarArgs = Abc_UtilStrsav( (char *)pUfarArgs ); +} +static void Cec_SprovePlanFree( Cec_SprovePlan_t * pPlan ) +{ + ABC_FREE( pPlan->pUfarArgs ); + pPlan->pUfarArgs = NULL; +} +static void Cec_SprovePlanDefault( Cec_SprovePlan_t * pPlan, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, const char * pUfarArgs ) { int nEngines; memset( pPlan, 0, sizeof(Cec_SprovePlan_t) ); @@ -336,8 +386,10 @@ static void Cec_SprovePlanDefault( Cec_SprovePlan_t * pPlan, int nProcs, int nTi pPlan->nTimeOut2 = nTimeOut2; pPlan->nTimeOut3 = nTimeOut3; pPlan->fUseUif = fUseUif; + pPlan->fPersistentUif = fUseUif ? 1 : 0; + Cec_SprovePlanSetUfarArgs( pPlan, pUfarArgs ); pPlan->nStages = 4; - Cec_SproveDeriveEngineList( nProcs, fUseUif, pPlan->Stages[0].RoundEngines, &nEngines ); + Cec_SproveDeriveEngineList( nProcs, fUseUif, pPlan->fPersistentUif, pPlan->Stages[0].RoundEngines, &nEngines ); pPlan->Stages[0].Id = 1; pPlan->Stages[0].fHasRound = 1; @@ -376,6 +428,7 @@ static void Cec_SprovePlanDefault( Cec_SprovePlan_t * pPlan, int nProcs, int nTi pPlan->Stages[3].RoundTimeout = nTimeOut3; pPlan->Stages[3].nRoundEngines = nEngines; memcpy( pPlan->Stages[3].RoundEngines, pPlan->Stages[0].RoundEngines, sizeof(int) * nEngines ); + pPlan->nTimeOutUif = pPlan->fPersistentUif ? Cec_SprovePlanTimeoutTotal( pPlan ) : 0; } static void Cec_SproveTraceWrite( Cec_SproveTrace_t * pTrace, const char * pFormat, ... ) { @@ -410,6 +463,10 @@ static void Cec_SproveTraceOpen( Cec_SproveTrace_t * pTrace, Gia_Man_t * p, Cec_ Cec_SproveTraceWrite( pTrace, "SPROVE_REPLAY 1" ); Cec_SproveTraceWrite( pTrace, "CASE %s", pProbName ? pProbName : "(none)" ); Cec_SproveTraceWrite( pTrace, "PARAMS P=%d T=%d U=%d W=%d UIF=%d", pPlan->nProcs, pPlan->nTimeOut, pPlan->nTimeOut2, pPlan->nTimeOut3, pPlan->fUseUif ); + if ( pPlan->fUseUif ) + Cec_SproveTraceWrite( pTrace, "UFAR mode=%s timeout=%d", pPlan->fPersistentUif ? "persistent" : "round", pPlan->nTimeOutUif ); + if ( pPlan->pUfarArgs && pPlan->pUfarArgs[0] ) + Cec_SproveTraceWrite( pTrace, "UFAR_ARGS %s", pPlan->pUfarArgs ); Cec_SproveTraceWrite( pTrace, "" ); Cec_SproveTraceWrite( pTrace, "PLAN_BEGIN" ); for ( i = 0; i < pPlan->nStages; i++ ) @@ -481,12 +538,29 @@ static int Cec_SproveReplayReadParamsInt( char * pFileName, Cec_SprovePlan_t * p pPlan->nTimeOut3 = atoi(Value); if ( !Cec_SproveFindValue(Buffer, "UIF=", Value, sizeof(Value)) ) break; pPlan->fUseUif = atoi(Value); + } + else if ( strncmp(Buffer, "UFAR_ARGS ", 10) == 0 ) + { + Cec_SproveTrimLineEnd( Buffer ); + Cec_SprovePlanSetUfarArgs( pPlan, Buffer + 10 ); + } + else if ( strncmp(Buffer, "UFAR ", 5) == 0 ) + { + if ( Cec_SproveFindValue(Buffer, "mode=", Value, sizeof(Value)) ) + pPlan->fPersistentUif = !strcmp(Value, "persistent"); + if ( Cec_SproveFindValue(Buffer, "timeout=", Value, sizeof(Value)) ) + pPlan->nTimeOutUif = atoi(Value); + } + else if ( pPlan->nProcs > 0 && (strncmp(Buffer, "PLAN_BEGIN", 10) == 0 || strncmp(Buffer, "OBSERVED_BEGIN", 14) == 0) ) + { + if ( pPlan->fUseUif && pPlan->nTimeOutUif == 0 ) + pPlan->nTimeOutUif = pPlan->fPersistentUif ? (pPlan->nTimeOut + pPlan->nTimeOut2 + 2 * pPlan->nTimeOut3) : 0; fclose( pFile ); return 1; } } fclose( pFile ); - return 0; + return pPlan->nProcs > 0; } static int Cec_SproveReplayReadPlan( char * pFileName, Cec_SprovePlan_t * pPlan ) { @@ -678,20 +752,35 @@ static Gia_Man_t * Cec_SproveRunReduce( Gia_Man_t * pInput, Cec_SproveStage_t * } return pOutput; } +static void Cec_SproveTakeSharedResult( Par_Share_t * pShare, int * pRetValue, int * pRetEngine ) +{ + if ( pShare == NULL || pRetValue == NULL || pRetEngine == NULL ) + return; + if ( *pRetValue == -1 && pShare->fSolved ) + { + *pRetValue = (int)pShare->Result; + *pRetEngine = pShare->iEngine; + } +} static int Cec_SproveExecutePlan( Gia_Man_t * p, Cec_SprovePlan_t * pPlan, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile ) { abctime clkTotal = Abc_Clock(), clkStage = 0; Par_ThData_t ThData[PAR_THR_MAX]; pthread_t WorkerThread[PAR_THR_MAX]; + Par_ThData_t UifData[1]; + pthread_t UifThread[1]; Par_Share_t Share; Cec_SproveTrace_t Trace; Gia_Man_t * pScorr = NULL, * pScorr2 = NULL; - int i, RetValue = -1, RetEngine = -1, fThreadsStarted = 0; + int UifEngines[1] = { PAR_ENGINE_UFAR }; + int i, RetValue = -1, RetEngine = -1, fThreadsStarted = 0, fUifStarted = 0; (void)fVeryVerbose; memset( &Share, 0, sizeof(Par_Share_t) ); memset( &Trace, 0, sizeof(Cec_SproveTrace_t) ); memset( ThData, 0, sizeof(ThData) ); memset( WorkerThread, 0, sizeof(WorkerThread) ); + memset( UifData, 0, sizeof(UifData) ); + memset( UifThread, 0, sizeof(UifThread) ); Abc_CexFreeP( &p->pCexComb ); Abc_CexFreeP( &p->pCexSeq ); if ( !fSilent && fVerbose ) @@ -700,10 +789,19 @@ static int Cec_SproveExecutePlan( Gia_Man_t * p, Cec_SprovePlan_t * pPlan, Wlc_N printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", pPlan->nProcs, pPlan->nTimeOut, fVerbose ); fflush( stdout ); Cec_SproveTraceOpen( &Trace, p, pPlan, pReplayFile ); + if ( pPlan->fUseUif && pPlan->fPersistentUif && pWlc != NULL ) + { + Cec_SproveTraceWrite( &Trace, "START kind=ufar mode=persistent timeout=%d t=%llu", + pPlan->nTimeOutUif, Cec_SproveClockToMs( Cec_SproveTraceTime(&Trace) ) ); + Cec_GiaInitThreads( UifData, 1, p, pPlan->nTimeOutUif, pPlan->nTimeOutUif, pWlc, pPlan->pUfarArgs, fVerbose, + UifThread, &Share, UifEngines, 0, SPROVE_NET_ORIG, &Trace ); + fUifStarted = 1; + } for ( i = 0; i < pPlan->nStages; i++ ) { Cec_SproveStage_t * pStage = &pPlan->Stages[i]; Gia_Man_t * pRoundNet = NULL, * pReduceNet = NULL, * pReduceOut = NULL; + Cec_SproveTakeSharedResult( &Share, &RetValue, &RetEngine ); if ( !Cec_SproveCheckGuard( pStage, RetValue, p, pScorr, pScorr2 ) ) { Cec_SproveTraceWrite( &Trace, "SKIP stage=%d reason=guard", pStage->Id ); @@ -719,7 +817,7 @@ static int Cec_SproveExecutePlan( Gia_Man_t * p, Cec_SprovePlan_t * pPlan, Wlc_N } Cec_SproveTraceWrite( &Trace, "START kind=round stage=%d net=%s timeout=%d t=%llu", pStage->Id, Cec_SproveNetName(pStage->RoundNet), pStage->RoundTimeout, Cec_SproveClockToMs( Cec_SproveTraceTime(&Trace) ) ); - Cec_GiaInitThreads( ThData, pStage->nRoundEngines, pRoundNet, pStage->RoundTimeout, pPlan->nTimeOut3, pWlc, fVerbose, + Cec_GiaInitThreads( ThData, pStage->nRoundEngines, pRoundNet, pStage->RoundTimeout, pStage->RoundTimeout, pWlc, pPlan->pUfarArgs, fVerbose, fThreadsStarted ? NULL : WorkerThread, &Share, pStage->RoundEngines, pStage->Id, pStage->RoundNet, &Trace ); fThreadsStarted = 1; } @@ -732,11 +830,13 @@ static int Cec_SproveExecutePlan( Gia_Man_t * p, Cec_SprovePlan_t * pPlan, Wlc_N { pReduceOut = Cec_SproveRunReduce( pReduceNet, pStage, &Share, &Trace, &clkStage, &RetValue, &RetEngine ); Cec_SproveSetNet( pStage->ReduceNetOut, &pScorr, &pScorr2, pReduceOut ); + Cec_SproveTakeSharedResult( &Share, &RetValue, &RetEngine ); } } if ( pStage->fHasRound ) { RetValue = Cec_GiaWaitThreads( ThData, pStage->nRoundEngines, p, RetValue, &RetEngine ); + Cec_SproveTakeSharedResult( &Share, &RetValue, &RetEngine ); Cec_SproveTraceWrite( &Trace, "STOP kind=round stage=%d net=%s result=%s winner=%s t=%llu", pStage->Id, Cec_SproveNetName(pStage->RoundNet), Cec_SproveResultName(RetValue), RetEngine >= 0 ? Cec_SolveEngineName(RetEngine) : "none", Cec_SproveClockToMs( Cec_SproveTraceTime(&Trace) ) ); @@ -752,8 +852,18 @@ static int Cec_SproveExecutePlan( Gia_Man_t * p, Cec_SprovePlan_t * pPlan, Wlc_N } } } + if ( fUifStarted ) + { + RetValue = Cec_GiaWaitThreads( UifData, 1, p, RetValue, &RetEngine ); + Cec_SproveTakeSharedResult( &Share, &RetValue, &RetEngine ); + Cec_SproveTraceWrite( &Trace, "STOP kind=ufar mode=persistent result=%s winner=%s t=%llu", + Cec_SproveResultName(RetValue), RetEngine == PAR_ENGINE_UFAR ? "ufar" : "other", + Cec_SproveClockToMs( Cec_SproveTraceTime(&Trace) ) ); + } if ( fThreadsStarted ) - Cec_GiaStopThreads( ThData, WorkerThread, pPlan->Stages[0].nRoundEngines > 0 ? pPlan->Stages[0].nRoundEngines : pPlan->nProcs + (pPlan->fUseUif ? 1 : 0) ); + Cec_GiaStopThreads( ThData, WorkerThread, pPlan->Stages[0].nRoundEngines ); + if ( fUifStarted ) + Cec_GiaStopThreads( UifData, UifThread, 1 ); Gia_ManStopP( &pScorr2 ); Gia_ManStopP( &pScorr ); if ( !fSilent ) @@ -920,7 +1030,7 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par if ( pThData && pThData->pWlc ) { g_pUfarShare = pThData->pShare; - RetValue = Ufar_ProveWithTimeout( pThData->pWlc, pThData->nTimeOutU, fVerbose, Cec_SProveStopUfar, 0 ); + RetValue = Ufar_ProveWithTimeout( pThData->pWlc, pThData->nTimeOutU, fVerbose, Cec_SProveStopUfar, 0, pThData->pUfarArgs ); g_pUfarShare = NULL; } } @@ -1072,7 +1182,7 @@ static void Cec_GiaStartThreads( Par_ThData_t * ThData, int nWorkers ) assert( status == 0 ); } } -static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare, int * pEngines, int StageId, int NetId, Cec_SproveTrace_t * pTrace ) +static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, const char * pUfarArgs, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare, int * pEngines, int StageId, int NetId, Cec_SproveTrace_t * pTrace ) { int i, status; assert( nWorkers <= PAR_THR_MAX ); @@ -1090,6 +1200,7 @@ static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * ThData[i].fVerbose = fVerbose; ThData[i].nTimeOutU= nTimeOutU; ThData[i].pWlc = pWlc; + ThData[i].pUfarArgs= pUfarArgs; ThData[i].WorkerId = i; ThData[i].StageId = StageId; ThData[i].NetId = NetId; @@ -1117,6 +1228,7 @@ static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * ThData[i].fVerbose = fVerbose; ThData[i].nTimeOutU= nTimeOutU; ThData[i].pWlc = pWlc; + ThData[i].pUfarArgs= pUfarArgs; ThData[i].WorkerId = i; ThData[i].StageId = StageId; ThData[i].NetId = NetId; @@ -1190,22 +1302,29 @@ int Cec_GiaReplayReadParams( char * pFileName, int * pnProcs, int * pnTimeOut, i *pnTimeOut3 = Plan.nTimeOut3; if ( pfUseUif ) *pfUseUif = Plan.fUseUif; + Cec_SprovePlanFree( &Plan ); return 1; } -int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile ) +int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile, char * pUfarArgs ) { Cec_SprovePlan_t Plan; - Cec_SprovePlanDefault( &Plan, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fUseUif ); + int RetValue; + Cec_SprovePlanDefault( &Plan, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fUseUif, pUfarArgs ); assert( nProcs >= 1 && nProcs <= 6 ); assert( nProcs + (fUseUif ? 1 : 0) <= PAR_THR_MAX ); - return Cec_SproveExecutePlan( p, &Plan, pWlc, fVerbose, fVeryVerbose, fSilent, pReplayFile ); + RetValue = Cec_SproveExecutePlan( p, &Plan, pWlc, fVerbose, fVeryVerbose, fSilent, pReplayFile ); + Cec_SprovePlanFree( &Plan ); + return RetValue; } int Cec_GiaReplayTest( Gia_Man_t * p, Wlc_Ntk_t * pWlc, char * pFileName, int fVerbose, int fVeryVerbose, int fSilent ) { Cec_SprovePlan_t Plan; + int RetValue; if ( !Cec_SproveReplayReadPlan( pFileName, &Plan ) ) return -1; - return Cec_SproveExecutePlan( p, &Plan, pWlc, fVerbose, fVeryVerbose, fSilent, NULL ); + RetValue = Cec_SproveExecutePlan( p, &Plan, pWlc, fVerbose, fVeryVerbose, fSilent, NULL ); + Cec_SprovePlanFree( &Plan ); + return RetValue; } #endif // pthreads are used diff --git a/src/proof/cec/module.make b/src/proof/cec/module.make index ed8deba98..d9d921e2d 100644 --- a/src/proof/cec/module.make +++ b/src/proof/cec/module.make @@ -3,6 +3,7 @@ SRC += src/proof/cec/cecCec.c \ src/proof/cec/cecClass.c \ src/proof/cec/cecCore.c \ src/proof/cec/cecCorr.c \ + src/proof/cec/cecCorrIncr.c \ src/proof/cec/cecIso.c \ src/proof/cec/cecMan.c \ src/proof/cec/cecPat.c \ diff --git a/src/sat/bmc/bmcBmcG.c b/src/sat/bmc/bmcBmcG.c index af2da1e2e..78321badb 100644 --- a/src/sat/bmc/bmcBmcG.c +++ b/src/sat/bmc/bmcBmcG.c @@ -362,6 +362,8 @@ int Bmcg_ManPerformOne( Gia_Man_t * pGia, Bmc_AndPar_t * pPars ) Abc_CexFreeP( &pGia->pCexSeq ); for ( f = 0; !pPars->nFramesMax || f < pPars->nFramesMax; f += pPars->nFramesAdd ) { + if ( pPars->pFuncProgress && pPars->pFuncProgress( pPars->pProgress, 0, 0 ) ) + break; Cnf_Dat_t * pCnf = Bmcg_ManAddNewCnf( p, f, pPars->nFramesAdd ); if ( pCnf == NULL ) { @@ -378,15 +380,21 @@ int Bmcg_ManPerformOne( Gia_Man_t * pGia, Bmc_AndPar_t * pPars ) assert( Gia_ManPoNum(p->pFrames) == (f + pPars->nFramesAdd) * Gia_ManPoNum(pGia) ); for ( k = 0; k < pPars->nFramesAdd; k++ ) { + if ( pPars->pFuncProgress && pPars->pFuncProgress( pPars->pProgress, 0, 0 ) ) + break; for ( i = 0; i < Gia_ManPoNum(pGia); i++ ) { abctime clk = Abc_Clock(); int iObj = Gia_ObjId( p->pFrames, Gia_ManCo(p->pFrames, (f+k) * Gia_ManPoNum(pGia) + i) ); int iLit = Abc_Var2Lit( Vec_IntEntry(&p->vFr2Sat, iObj), 0 ); + if ( pPars->pFuncProgress && pPars->pFuncProgress( pPars->pProgress, 0, 0 ) ) + break; if ( pPars->nTimeOut && (Abc_Clock() - clkStart)/CLOCKS_PER_SEC >= pPars->nTimeOut ) break; status = bmcg_sat_solver_solve( p->pSats[0], &iLit, 1 ); p->timeSat += Abc_Clock() - clk; + if ( pPars->pFuncProgress && pPars->pFuncProgress( pPars->pProgress, 0, 0 ) ) + break; if ( status == -1 ) // unsat { if ( i == Gia_ManPoNum(pGia)-1 ) diff --git a/src/sat/cadical/cadical_file.cpp b/src/sat/cadical/cadical_file.cpp index d48193e93..c4225dbeb 100644 --- a/src/sat/cadical/cadical_file.cpp +++ b/src/sat/cadical/cadical_file.cpp @@ -41,7 +41,7 @@ extern "C" { #endif -#if defined(__APPLE__) || defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) extern "C" { #include @@ -293,7 +293,7 @@ FILE *File::read_pipe (Internal *internal, const char *fmt, const int *sig, #if !defined(_WIN32) && !defined(__wasm) -#if defined(__APPLE__) || defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) static std::mutex compressed_file_writing_mutex; #endif @@ -312,7 +312,7 @@ FILE *File::write_pipe (Internal *internal, const char *command, char *absolute_command_path = find_program (argv[0]); int pipe_fds[2], out; FILE *res = 0; -#if defined(__APPLE__) || defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) compressed_file_writing_mutex.lock (); #endif if (!absolute_command_path) @@ -369,7 +369,7 @@ FILE *File::write_pipe (Internal *internal, const char *command, #ifdef CADICAL_QUIET (void) internal; #endif -#if defined(__APPLE__) || defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) if (!res) compressed_file_writing_mutex.unlock (); #endif @@ -475,7 +475,7 @@ void File::close (bool print) { MSG ("closing output pipe to write '%s'", name ()); fclose (file); waitpid (child_pid, 0, 0); -#if defined(__APPLE__) || defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) compressed_file_writing_mutex.unlock (); #endif } diff --git a/src/sat/cnf/cnfMan.c b/src/sat/cnf/cnfMan.c index 16a4cf219..cfcc437f1 100644 --- a/src/sat/cnf/cnfMan.c +++ b/src/sat/cnf/cnfMan.c @@ -9,7 +9,7 @@ Synopsis [] Author [Alan Mishchenko] - + Affiliation [UC Berkeley] Date [Ver. 1.0. Started - April 28, 2007.] @@ -25,13 +25,47 @@ ABC_NAMESPACE_IMPL_START - //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// -static inline int Cnf_Lit2Var( int Lit ) { return (Lit & 1)? -(Lit >> 1)-1 : (Lit >> 1)+1; } -static inline int Cnf_Lit2Var2( int Lit ) { return (Lit & 1)? -(Lit >> 1) : (Lit >> 1); } +static inline int Cnf_Lit2Var(int Lit) { return (Lit & 1) ? -(Lit >> 1) - 1 : (Lit >> 1) + 1; } +static inline int Cnf_Lit2Var2(int Lit) { return (Lit & 1) ? -(Lit >> 1) : (Lit >> 1); } + +// Emits unit clauses for DIMACS variables that are declared in the header +// but never referenced in any clause. After strash, a primary input that +// is wired directly to a primary output has no fanout into any AND node, +// so the Tseitin encoder leaves the corresponding DIMACS variable without +// any connecting clause. Such a dangling variable silently doubles the +// model count of the output formula, breaking #SAT and uniform sampling. +// Forcing each unreferenced declared variable to a fixed polarity restores +// the original number of satisfying assignments without affecting the set +// of assignments over live variables. Pass pFile == NULL to only count. +static int Cnf_DataWriteDanglingUnitClauses(FILE *pFile, Cnf_Dat_t *p) +{ + char *pUsed; + int *pLit, *pStop; + int i, v, iVar, nExtra = 0; + if (p->nVars <= 0) + return 0; + pUsed = ABC_CALLOC(char, p->nVars + 1); + for (i = 0; i < p->nClauses; i++) + for (pLit = p->pClauses[i], pStop = p->pClauses[i + 1]; pLit < pStop; pLit++) + { + iVar = (*pLit >> 1) + 1; + if (iVar >= 1 && iVar <= p->nVars) + pUsed[iVar] = 1; + } + for (v = 1; v <= p->nVars; v++) + if (!pUsed[v]) + { + if (pFile) + fprintf(pFile, "-%d 0\n", v); + nExtra++; + } + ABC_FREE(pUsed); + return nExtra; +} //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// @@ -42,29 +76,29 @@ static inline int Cnf_Lit2Var2( int Lit ) { return (Lit & 1)? -(Lit >> 1) Synopsis [Starts the fraiging manager.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -Cnf_Man_t * Cnf_ManStart() +Cnf_Man_t *Cnf_ManStart() { - Cnf_Man_t * p; + Cnf_Man_t *p; int i; // allocate the manager - p = ABC_ALLOC( Cnf_Man_t, 1 ); - memset( p, 0, sizeof(Cnf_Man_t) ); + p = ABC_ALLOC(Cnf_Man_t, 1); + memset(p, 0, sizeof(Cnf_Man_t)); // derive internal data structures - Cnf_ReadMsops( &p->pSopSizes, &p->pSops ); + Cnf_ReadMsops(&p->pSopSizes, &p->pSops); // allocate memory manager for cuts p->pMemCuts = Aig_MmFlexStart(); p->nMergeLimit = 10; // allocate temporary truth tables - p->pTruths[0] = ABC_ALLOC( unsigned, 4 * Abc_TruthWordNum(p->nMergeLimit) ); - for ( i = 1; i < 4; i++ ) - p->pTruths[i] = p->pTruths[i-1] + Abc_TruthWordNum(p->nMergeLimit); - p->vMemory = Vec_IntAlloc( 1 << 18 ); + p->pTruths[0] = ABC_ALLOC(unsigned, 4 * Abc_TruthWordNum(p->nMergeLimit)); + for (i = 1; i < 4; i++) + p->pTruths[i] = p->pTruths[i - 1] + Abc_TruthWordNum(p->nMergeLimit); + p->vMemory = Vec_IntAlloc(1 << 18); return p; } @@ -73,21 +107,21 @@ Cnf_Man_t * Cnf_ManStart() Synopsis [Stops the fraiging manager.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void Cnf_ManStop( Cnf_Man_t * p ) +void Cnf_ManStop(Cnf_Man_t *p) { - Vec_IntFree( p->vMemory ); - ABC_FREE( p->pTruths[0] ); - Aig_MmFlexStop( p->pMemCuts, 0 ); - ABC_FREE( p->pSopSizes ); - ABC_FREE( p->pSops[1] ); - ABC_FREE( p->pSops ); - ABC_FREE( p ); + Vec_IntFree(p->vMemory); + ABC_FREE(p->pTruths[0]); + Aig_MmFlexStop(p->pMemCuts, 0); + ABC_FREE(p->pSopSizes); + ABC_FREE(p->pSops[1]); + ABC_FREE(p->pSops); + ABC_FREE(p); } /**Function************************************************************* @@ -95,18 +129,19 @@ void Cnf_ManStop( Cnf_Man_t * p ) Synopsis [Returns the array of CI IDs.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -Vec_Int_t * Cnf_DataCollectPiSatNums( Cnf_Dat_t * pCnf, Aig_Man_t * p ) +Vec_Int_t *Cnf_DataCollectPiSatNums(Cnf_Dat_t *pCnf, Aig_Man_t *p) { - Aig_Obj_t * pObj; int i; - Vec_Int_t * vCiIds = Vec_IntAlloc( Aig_ManCiNum(p) ); - Aig_ManForEachCi( p, pObj, i ) - Vec_IntPush( vCiIds, pCnf->pVarNums[pObj->Id] ); + Aig_Obj_t *pObj; + int i; + Vec_Int_t *vCiIds = Vec_IntAlloc(Aig_ManCiNum(p)); + Aig_ManForEachCi(p, pObj, i) + Vec_IntPush(vCiIds, pCnf->pVarNums[pObj->Id]); return vCiIds; } @@ -115,25 +150,25 @@ Vec_Int_t * Cnf_DataCollectPiSatNums( Cnf_Dat_t * pCnf, Aig_Man_t * p ) Synopsis [Allocates the new CNF.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -Cnf_Dat_t * Cnf_DataAlloc( Aig_Man_t * pAig, int nVars, int nClauses, int nLiterals ) +Cnf_Dat_t *Cnf_DataAlloc(Aig_Man_t *pAig, int nVars, int nClauses, int nLiterals) { - Cnf_Dat_t * pCnf; - pCnf = ABC_CALLOC( Cnf_Dat_t, 1 ); + Cnf_Dat_t *pCnf; + pCnf = ABC_CALLOC(Cnf_Dat_t, 1); pCnf->pMan = pAig; pCnf->nVars = nVars; pCnf->nClauses = nClauses; pCnf->nLiterals = nLiterals; - pCnf->pClauses = ABC_ALLOC( int *, nClauses + 1 ); - pCnf->pClauses[0] = ABC_ALLOC( int, nLiterals ); + pCnf->pClauses = ABC_ALLOC(int *, nClauses + 1); + pCnf->pClauses[0] = ABC_ALLOC(int, nLiterals); pCnf->pClauses[nClauses] = pCnf->pClauses[0] + nLiterals; - if ( pCnf->pVarNums ) - pCnf->pVarNums = ABC_FALLOC( int, Aig_ManObjNumMax(pAig) ); + if (pCnf->pVarNums) + pCnf->pVarNums = ABC_FALLOC(int, Aig_ManObjNumMax(pAig)); return pCnf; } @@ -142,54 +177,55 @@ Cnf_Dat_t * Cnf_DataAlloc( Aig_Man_t * pAig, int nVars, int nClauses, int nLiter Synopsis [Allocates the new CNF.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -Cnf_Dat_t * Cnf_DataDup( Cnf_Dat_t * p ) +Cnf_Dat_t *Cnf_DataDup(Cnf_Dat_t *p) { - Cnf_Dat_t * pCnf; + Cnf_Dat_t *pCnf; int i; - pCnf = Cnf_DataAlloc( p->pMan, p->nVars, p->nClauses, p->nLiterals ); - memcpy( pCnf->pClauses[0], p->pClauses[0], sizeof(int) * p->nLiterals ); - if ( p->pVarNums ) - memcpy( pCnf->pVarNums, p->pVarNums, sizeof(int) * Aig_ManObjNumMax(p->pMan) ); - for ( i = 1; i < p->nClauses; i++ ) + pCnf = Cnf_DataAlloc(p->pMan, p->nVars, p->nClauses, p->nLiterals); + memcpy(pCnf->pClauses[0], p->pClauses[0], sizeof(int) * p->nLiterals); + if (p->pVarNums) + memcpy(pCnf->pVarNums, p->pVarNums, sizeof(int) * Aig_ManObjNumMax(p->pMan)); + for (i = 1; i < p->nClauses; i++) pCnf->pClauses[i] = pCnf->pClauses[0] + (p->pClauses[i] - p->pClauses[0]); return pCnf; } -Cnf_Dat_t * Cnf_DataDupCof( Cnf_Dat_t * p, int Lit ) +Cnf_Dat_t *Cnf_DataDupCof(Cnf_Dat_t *p, int Lit) { - Cnf_Dat_t * pCnf; + Cnf_Dat_t *pCnf; int i; - pCnf = Cnf_DataAlloc( p->pMan, p->nVars, p->nClauses+1, p->nLiterals+1 ); - memcpy( pCnf->pClauses[0], p->pClauses[0], sizeof(int) * p->nLiterals ); - if ( pCnf->pVarNums ) - memcpy( pCnf->pVarNums, p->pVarNums, sizeof(int) * Aig_ManObjNumMax(p->pMan) ); - for ( i = 1; i < p->nClauses; i++ ) + pCnf = Cnf_DataAlloc(p->pMan, p->nVars, p->nClauses + 1, p->nLiterals + 1); + memcpy(pCnf->pClauses[0], p->pClauses[0], sizeof(int) * p->nLiterals); + if (pCnf->pVarNums) + memcpy(pCnf->pVarNums, p->pVarNums, sizeof(int) * Aig_ManObjNumMax(p->pMan)); + for (i = 1; i < p->nClauses; i++) pCnf->pClauses[i] = pCnf->pClauses[0] + (p->pClauses[i] - p->pClauses[0]); pCnf->pClauses[p->nClauses] = pCnf->pClauses[0] + p->nLiterals; pCnf->pClauses[p->nClauses][0] = Lit; - assert( pCnf->pClauses[p->nClauses+1] == pCnf->pClauses[0] + p->nLiterals+1 ); + assert(pCnf->pClauses[p->nClauses + 1] == pCnf->pClauses[0] + p->nLiterals + 1); return pCnf; } -Cnf_Dat_t * Cnf_DataDupCofArray( Cnf_Dat_t * p, Vec_Int_t * vLits ) +Cnf_Dat_t *Cnf_DataDupCofArray(Cnf_Dat_t *p, Vec_Int_t *vLits) { - Cnf_Dat_t * pCnf; + Cnf_Dat_t *pCnf; int i, iLit; - pCnf = Cnf_DataAlloc( p->pMan, p->nVars, p->nClauses+Vec_IntSize(vLits), p->nLiterals+Vec_IntSize(vLits) ); - memcpy( pCnf->pClauses[0], p->pClauses[0], sizeof(int) * p->nLiterals ); - if ( pCnf->pVarNums ) - memcpy( pCnf->pVarNums, p->pVarNums, sizeof(int) * Aig_ManObjNumMax(p->pMan) ); - for ( i = 1; i < p->nClauses; i++ ) + pCnf = Cnf_DataAlloc(p->pMan, p->nVars, p->nClauses + Vec_IntSize(vLits), p->nLiterals + Vec_IntSize(vLits)); + memcpy(pCnf->pClauses[0], p->pClauses[0], sizeof(int) * p->nLiterals); + if (pCnf->pVarNums) + memcpy(pCnf->pVarNums, p->pVarNums, sizeof(int) * Aig_ManObjNumMax(p->pMan)); + for (i = 1; i < p->nClauses; i++) pCnf->pClauses[i] = pCnf->pClauses[0] + (p->pClauses[i] - p->pClauses[0]); - Vec_IntForEachEntry( vLits, iLit, i ) { - pCnf->pClauses[p->nClauses+i] = pCnf->pClauses[0] + p->nLiterals+i; - pCnf->pClauses[p->nClauses+i][0] = iLit; + Vec_IntForEachEntry(vLits, iLit, i) + { + pCnf->pClauses[p->nClauses + i] = pCnf->pClauses[0] + p->nLiterals + i; + pCnf->pClauses[p->nClauses + i][0] = iLit; } - assert( pCnf->pClauses[p->nClauses+Vec_IntSize(vLits)] == pCnf->pClauses[0] + p->nLiterals+Vec_IntSize(vLits) ); + assert(pCnf->pClauses[p->nClauses + Vec_IntSize(vLits)] == pCnf->pClauses[0] + p->nLiterals + Vec_IntSize(vLits)); return pCnf; } @@ -198,24 +234,24 @@ Cnf_Dat_t * Cnf_DataDupCofArray( Cnf_Dat_t * p, Vec_Int_t * vLits ) Synopsis [] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void Cnf_DataFree( Cnf_Dat_t * p ) +void Cnf_DataFree(Cnf_Dat_t *p) { - if ( p == NULL ) + if (p == NULL) return; - Vec_IntFreeP( &p->vMapping ); - ABC_FREE( p->pClaPols ); - ABC_FREE( p->pObj2Clause ); - ABC_FREE( p->pObj2Count ); - ABC_FREE( p->pClauses[0] ); - ABC_FREE( p->pClauses ); - ABC_FREE( p->pVarNums ); - ABC_FREE( p ); + Vec_IntFreeP(&p->vMapping); + ABC_FREE(p->pClaPols); + ABC_FREE(p->pObj2Clause); + ABC_FREE(p->pObj2Count); + ABC_FREE(p->pClauses[0]); + ABC_FREE(p->pClauses); + ABC_FREE(p->pVarNums); + ABC_FREE(p); } /**Function************************************************************* @@ -223,40 +259,39 @@ void Cnf_DataFree( Cnf_Dat_t * p ) Synopsis [] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void Cnf_DataLift( Cnf_Dat_t * p, int nVarsPlus ) +void Cnf_DataLift(Cnf_Dat_t *p, int nVarsPlus) { - Aig_Obj_t * pObj; + Aig_Obj_t *pObj; int v; - if ( p->pMan ) + if (p->pMan) { - Aig_ManForEachObj( p->pMan, pObj, v ) - if ( p->pVarNums[pObj->Id] >= 0 ) - p->pVarNums[pObj->Id] += nVarsPlus; + Aig_ManForEachObj(p->pMan, pObj, v) if (p->pVarNums[pObj->Id] >= 0) + p->pVarNums[pObj->Id] += nVarsPlus; } - for ( v = 0; v < p->nLiterals; v++ ) - p->pClauses[0][v] += 2*nVarsPlus; + for (v = 0; v < p->nLiterals; v++) + p->pClauses[0][v] += 2 * nVarsPlus; } -void Cnf_DataCollectFlipLits( Cnf_Dat_t * p, int iFlipVar, Vec_Int_t * vFlips ) +void Cnf_DataCollectFlipLits(Cnf_Dat_t *p, int iFlipVar, Vec_Int_t *vFlips) { int v; - assert( p->pMan == NULL ); - Vec_IntClear( vFlips ); - for ( v = 0; v < p->nLiterals; v++ ) - if ( Abc_Lit2Var(p->pClauses[0][v]) == iFlipVar ) - Vec_IntPush( vFlips, v ); + assert(p->pMan == NULL); + Vec_IntClear(vFlips); + for (v = 0; v < p->nLiterals; v++) + if (Abc_Lit2Var(p->pClauses[0][v]) == iFlipVar) + Vec_IntPush(vFlips, v); } -void Cnf_DataLiftAndFlipLits( Cnf_Dat_t * p, int nVarsPlus, Vec_Int_t * vLits ) +void Cnf_DataLiftAndFlipLits(Cnf_Dat_t *p, int nVarsPlus, Vec_Int_t *vLits) { int i, iLit; - assert( p->pMan == NULL ); - Vec_IntForEachEntry( vLits, iLit, i ) - p->pClauses[0][iLit] = Abc_LitNot(p->pClauses[0][iLit]) + 2*nVarsPlus; + assert(p->pMan == NULL); + Vec_IntForEachEntry(vLits, iLit, i) + p->pClauses[0][iLit] = Abc_LitNot(p->pClauses[0][iLit]) + 2 * nVarsPlus; } /**Function************************************************************* @@ -264,24 +299,24 @@ void Cnf_DataLiftAndFlipLits( Cnf_Dat_t * p, int nVarsPlus, Vec_Int_t * vLits ) Synopsis [] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void Cnf_DataPrint( Cnf_Dat_t * p, int fReadable ) +void Cnf_DataPrint(Cnf_Dat_t *p, int fReadable) { - FILE * pFile = stdout; - int * pLit, * pStop, i; - fprintf( pFile, "p cnf %d %d\n", p->nVars, p->nClauses ); - for ( i = 0; i < p->nClauses; i++ ) + FILE *pFile = stdout; + int *pLit, *pStop, i; + fprintf(pFile, "p cnf %d %d\n", p->nVars, p->nClauses); + for (i = 0; i < p->nClauses; i++) { - for ( pLit = p->pClauses[i], pStop = p->pClauses[i+1]; pLit < pStop; pLit++ ) - fprintf( pFile, "%s%d ", Abc_LitIsCompl(*pLit) ? "-":"", fReadable? Abc_Lit2Var(*pLit) : Abc_Lit2Var(*pLit)+1 ); - fprintf( pFile, "\n" ); + for (pLit = p->pClauses[i], pStop = p->pClauses[i + 1]; pLit < pStop; pLit++) + fprintf(pFile, "%s%d ", Abc_LitIsCompl(*pLit) ? "-" : "", fReadable ? Abc_Lit2Var(*pLit) : Abc_Lit2Var(*pLit) + 1); + fprintf(pFile, "\n"); } - fprintf( pFile, "\n" ); + fprintf(pFile, "\n"); } /**Function************************************************************* @@ -289,88 +324,88 @@ void Cnf_DataPrint( Cnf_Dat_t * p, int fReadable ) Synopsis [Writes CNF into a file.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void Cnf_DataWriteIntoFileGz( Cnf_Dat_t * p, char * pFileName, int fReadable, Vec_Int_t * vForAlls, Vec_Int_t * vExists ) +void Cnf_DataWriteIntoFileGz(Cnf_Dat_t *p, char *pFileName, int fReadable, Vec_Int_t *vForAlls, Vec_Int_t *vExists) { gzFile pFile; - int * pLit, * pStop, i, VarId; - pFile = gzopen( pFileName, "wb" ); - if ( pFile == NULL ) + int *pLit, *pStop, i, VarId; + pFile = gzopen(pFileName, "wb"); + if (pFile == NULL) { - printf( "Cnf_WriteIntoFile(): Output file cannot be opened.\n" ); + printf("Cnf_WriteIntoFile(): Output file cannot be opened.\n"); return; } - gzprintf( pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n" ); - gzprintf( pFile, "p cnf %d %d\n", p->nVars, p->nClauses ); - if ( vForAlls ) + gzprintf(pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n"); + gzprintf(pFile, "p cnf %d %d\n", p->nVars, p->nClauses); + if (vForAlls) { - gzprintf( pFile, "a " ); - Vec_IntForEachEntry( vForAlls, VarId, i ) - gzprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - gzprintf( pFile, "0\n" ); + gzprintf(pFile, "a "); + Vec_IntForEachEntry(vForAlls, VarId, i) + gzprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + gzprintf(pFile, "0\n"); } - if ( vExists ) + if (vExists) { - gzprintf( pFile, "e " ); - Vec_IntForEachEntry( vExists, VarId, i ) - gzprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - gzprintf( pFile, "0\n" ); + gzprintf(pFile, "e "); + Vec_IntForEachEntry(vExists, VarId, i) + gzprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + gzprintf(pFile, "0\n"); } - for ( i = 0; i < p->nClauses; i++ ) + for (i = 0; i < p->nClauses; i++) { - for ( pLit = p->pClauses[i], pStop = p->pClauses[i+1]; pLit < pStop; pLit++ ) - gzprintf( pFile, "%d ", fReadable? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit) ); - gzprintf( pFile, "0\n" ); + for (pLit = p->pClauses[i], pStop = p->pClauses[i + 1]; pLit < pStop; pLit++) + gzprintf(pFile, "%d ", fReadable ? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit)); + gzprintf(pFile, "0\n"); } - gzprintf( pFile, "\n" ); - gzclose( pFile ); + gzprintf(pFile, "\n"); + gzclose(pFile); } -void Cnf_DataWriteIntoFileInvGz( Cnf_Dat_t * p, char * pFileName, int fReadable, Vec_Int_t * vExists1, Vec_Int_t * vForAlls, Vec_Int_t * vExists2 ) +void Cnf_DataWriteIntoFileInvGz(Cnf_Dat_t *p, char *pFileName, int fReadable, Vec_Int_t *vExists1, Vec_Int_t *vForAlls, Vec_Int_t *vExists2) { gzFile pFile; - int * pLit, * pStop, i, VarId; - pFile = gzopen( pFileName, "wb" ); - if ( pFile == NULL ) + int *pLit, *pStop, i, VarId; + pFile = gzopen(pFileName, "wb"); + if (pFile == NULL) { - printf( "Cnf_WriteIntoFile(): Output file cannot be opened.\n" ); + printf("Cnf_WriteIntoFile(): Output file cannot be opened.\n"); return; } - gzprintf( pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n" ); - gzprintf( pFile, "p cnf %d %d\n", p->nVars, p->nClauses ); - if ( vExists1 ) + gzprintf(pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n"); + gzprintf(pFile, "p cnf %d %d\n", p->nVars, p->nClauses); + if (vExists1) { - gzprintf( pFile, "e " ); - Vec_IntForEachEntry( vExists1, VarId, i ) - gzprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - gzprintf( pFile, "0\n" ); + gzprintf(pFile, "e "); + Vec_IntForEachEntry(vExists1, VarId, i) + gzprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + gzprintf(pFile, "0\n"); } - if ( vForAlls ) + if (vForAlls) { - gzprintf( pFile, "a " ); - Vec_IntForEachEntry( vForAlls, VarId, i ) - gzprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - gzprintf( pFile, "0\n" ); + gzprintf(pFile, "a "); + Vec_IntForEachEntry(vForAlls, VarId, i) + gzprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + gzprintf(pFile, "0\n"); } - if ( vExists2 ) + if (vExists2) { - gzprintf( pFile, "e " ); - Vec_IntForEachEntry( vExists2, VarId, i ) - gzprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - gzprintf( pFile, "0\n" ); + gzprintf(pFile, "e "); + Vec_IntForEachEntry(vExists2, VarId, i) + gzprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + gzprintf(pFile, "0\n"); } - for ( i = 0; i < p->nClauses; i++ ) + for (i = 0; i < p->nClauses; i++) { - for ( pLit = p->pClauses[i], pStop = p->pClauses[i+1]; pLit < pStop; pLit++ ) - gzprintf( pFile, "%d ", fReadable? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit) ); - gzprintf( pFile, "0\n" ); + for (pLit = p->pClauses[i], pStop = p->pClauses[i + 1]; pLit < pStop; pLit++) + gzprintf(pFile, "%d ", fReadable ? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit)); + gzprintf(pFile, "0\n"); } - gzprintf( pFile, "\n" ); - gzclose( pFile ); + gzprintf(pFile, "\n"); + gzclose(pFile); } /**Function************************************************************* @@ -378,98 +413,101 @@ void Cnf_DataWriteIntoFileInvGz( Cnf_Dat_t * p, char * pFileName, int fReadable, Synopsis [Writes CNF into a file.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void Cnf_DataWriteIntoFile( Cnf_Dat_t * p, char * pFileName, int fReadable, Vec_Int_t * vForAlls, Vec_Int_t * vExists ) +void Cnf_DataWriteIntoFile(Cnf_Dat_t *p, char *pFileName, int fReadable, Vec_Int_t *vForAlls, Vec_Int_t *vExists) { - FILE * pFile; - int * pLit, * pStop, i, VarId; - if ( !strncmp(pFileName+strlen(pFileName)-3,".gz",3) ) + FILE *pFile; + int *pLit, *pStop, i, VarId, nExtra; + if (!strncmp(pFileName + strlen(pFileName) - 3, ".gz", 3)) { - Cnf_DataWriteIntoFileGz( p, pFileName, fReadable, vForAlls, vExists ); + Cnf_DataWriteIntoFileGz(p, pFileName, fReadable, vForAlls, vExists); return; } - pFile = fopen( pFileName, "w" ); - if ( pFile == NULL ) + pFile = fopen(pFileName, "w"); + if (pFile == NULL) { - printf( "Cnf_WriteIntoFile(): Output file cannot be opened.\n" ); + printf("Cnf_WriteIntoFile(): Output file cannot be opened.\n"); return; } - fprintf( pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n" ); - fprintf( pFile, "p cnf %d %d\n", p->nVars, p->nClauses ); - if ( vForAlls ) + nExtra = Cnf_DataWriteDanglingUnitClauses(NULL, p); + fprintf(pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n"); + fprintf(pFile, "p cnf %d %d\n", p->nVars, p->nClauses + nExtra); + if (vForAlls) { - fprintf( pFile, "a " ); - Vec_IntForEachEntry( vForAlls, VarId, i ) - fprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - fprintf( pFile, "0\n" ); + fprintf(pFile, "a "); + Vec_IntForEachEntry(vForAlls, VarId, i) + fprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + fprintf(pFile, "0\n"); } - if ( vExists ) + if (vExists) { - fprintf( pFile, "e " ); - Vec_IntForEachEntry( vExists, VarId, i ) - fprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - fprintf( pFile, "0\n" ); + fprintf(pFile, "e "); + Vec_IntForEachEntry(vExists, VarId, i) + fprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + fprintf(pFile, "0\n"); } - for ( i = 0; i < p->nClauses; i++ ) + for (i = 0; i < p->nClauses; i++) { - for ( pLit = p->pClauses[i], pStop = p->pClauses[i+1]; pLit < pStop; pLit++ ) - fprintf( pFile, "%d ", fReadable? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit) ); - fprintf( pFile, "0\n" ); + for (pLit = p->pClauses[i], pStop = p->pClauses[i + 1]; pLit < pStop; pLit++) + fprintf(pFile, "%d ", fReadable ? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit)); + fprintf(pFile, "0\n"); } - fprintf( pFile, "\n" ); - fclose( pFile ); + if (nExtra) + Cnf_DataWriteDanglingUnitClauses(pFile, p); + fprintf(pFile, "\n"); + fclose(pFile); } -void Cnf_DataWriteIntoFileInv( Cnf_Dat_t * p, char * pFileName, int fReadable, Vec_Int_t * vExists1, Vec_Int_t * vForAlls, Vec_Int_t * vExists2 ) +void Cnf_DataWriteIntoFileInv(Cnf_Dat_t *p, char *pFileName, int fReadable, Vec_Int_t *vExists1, Vec_Int_t *vForAlls, Vec_Int_t *vExists2) { - FILE * pFile; - int * pLit, * pStop, i, VarId; - if ( !strncmp(pFileName+strlen(pFileName)-3,".gz",3) ) + FILE *pFile; + int *pLit, *pStop, i, VarId; + if (!strncmp(pFileName + strlen(pFileName) - 3, ".gz", 3)) { - Cnf_DataWriteIntoFileInvGz( p, pFileName, fReadable, vExists1, vForAlls, vExists2 ); + Cnf_DataWriteIntoFileInvGz(p, pFileName, fReadable, vExists1, vForAlls, vExists2); return; } - pFile = fopen( pFileName, "w" ); - if ( pFile == NULL ) + pFile = fopen(pFileName, "w"); + if (pFile == NULL) { - printf( "Cnf_WriteIntoFile(): Output file cannot be opened.\n" ); + printf("Cnf_WriteIntoFile(): Output file cannot be opened.\n"); return; } - fprintf( pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n" ); - fprintf( pFile, "p cnf %d %d\n", p->nVars, p->nClauses ); - if ( vExists1 ) + fprintf(pFile, "c Result of efficient AIG-to-CNF conversion using package CNF\n"); + fprintf(pFile, "p cnf %d %d\n", p->nVars, p->nClauses); + if (vExists1) { - fprintf( pFile, "e " ); - Vec_IntForEachEntry( vExists1, VarId, i ) - fprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - fprintf( pFile, "0\n" ); + fprintf(pFile, "e "); + Vec_IntForEachEntry(vExists1, VarId, i) + fprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + fprintf(pFile, "0\n"); } - if ( vForAlls ) + if (vForAlls) { - fprintf( pFile, "a " ); - Vec_IntForEachEntry( vForAlls, VarId, i ) - fprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - fprintf( pFile, "0\n" ); + fprintf(pFile, "a "); + Vec_IntForEachEntry(vForAlls, VarId, i) + fprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + fprintf(pFile, "0\n"); } - if ( vExists2 ) + if (vExists2) { - fprintf( pFile, "e " ); - Vec_IntForEachEntry( vExists2, VarId, i ) - fprintf( pFile, "%d ", fReadable? VarId : VarId+1 ); - fprintf( pFile, "0\n" ); + fprintf(pFile, "e "); + Vec_IntForEachEntry(vExists2, VarId, i) + fprintf(pFile, "%d ", fReadable ? VarId : VarId + 1); + fprintf(pFile, "0\n"); } - for ( i = 0; i < p->nClauses; i++ ) + for (i = 0; i < p->nClauses; i++) { - for ( pLit = p->pClauses[i], pStop = p->pClauses[i+1]; pLit < pStop; pLit++ ) - fprintf( pFile, "%d ", fReadable? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit) ); - fprintf( pFile, "0\n" ); + for (pLit = p->pClauses[i], pStop = p->pClauses[i + 1]; pLit < pStop; pLit++) + fprintf(pFile, "%d ", fReadable ? Cnf_Lit2Var2(*pLit) : Cnf_Lit2Var(*pLit)); + fprintf(pFile, "0\n"); } - fprintf( pFile, "\n" ); - fclose( pFile ); + fprintf(pFile, "\n"); + fclose(pFile); } /**Function************************************************************* @@ -477,89 +515,89 @@ void Cnf_DataWriteIntoFileInv( Cnf_Dat_t * p, char * pFileName, int fReadable, V Synopsis [Writes CNF into a file.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void * Cnf_DataWriteIntoSolverInt( void * pSolver, Cnf_Dat_t * p, int nFrames, int fInit ) +void *Cnf_DataWriteIntoSolverInt(void *pSolver, Cnf_Dat_t *p, int nFrames, int fInit) { - sat_solver * pSat = (sat_solver *)pSolver; + sat_solver *pSat = (sat_solver *)pSolver; int i, f, status; - assert( nFrames > 0 ); - assert( pSat ); -// pSat = sat_solver_new(); - sat_solver_setnvars( pSat, p->nVars * nFrames ); - for ( i = 0; i < p->nClauses; i++ ) + assert(nFrames > 0); + assert(pSat); + // pSat = sat_solver_new(); + sat_solver_setnvars(pSat, p->nVars * nFrames); + for (i = 0; i < p->nClauses; i++) { - if ( !sat_solver_addclause( pSat, p->pClauses[i], p->pClauses[i+1] ) ) + if (!sat_solver_addclause(pSat, p->pClauses[i], p->pClauses[i + 1])) { - sat_solver_delete( pSat ); + sat_solver_delete(pSat); return NULL; } } - if ( nFrames > 1 ) + if (nFrames > 1) { - Aig_Obj_t * pObjLo, * pObjLi; - int nLitsAll, * pLits, Lits[2]; + Aig_Obj_t *pObjLo, *pObjLi; + int nLitsAll, *pLits, Lits[2]; nLitsAll = 2 * p->nVars; pLits = p->pClauses[0]; - for ( f = 1; f < nFrames; f++ ) + for (f = 1; f < nFrames; f++) { // add equality of register inputs/outputs for different timeframes - Aig_ManForEachLiLoSeq( p->pMan, pObjLi, pObjLo, i ) + Aig_ManForEachLiLoSeq(p->pMan, pObjLi, pObjLo, i) { - Lits[0] = (f-1)*nLitsAll + toLitCond( p->pVarNums[pObjLi->Id], 0 ); - Lits[1] = f *nLitsAll + toLitCond( p->pVarNums[pObjLo->Id], 1 ); - if ( !sat_solver_addclause( pSat, Lits, Lits + 2 ) ) + Lits[0] = (f - 1) * nLitsAll + toLitCond(p->pVarNums[pObjLi->Id], 0); + Lits[1] = f * nLitsAll + toLitCond(p->pVarNums[pObjLo->Id], 1); + if (!sat_solver_addclause(pSat, Lits, Lits + 2)) { - sat_solver_delete( pSat ); + sat_solver_delete(pSat); return NULL; } Lits[0]++; Lits[1]--; - if ( !sat_solver_addclause( pSat, Lits, Lits + 2 ) ) + if (!sat_solver_addclause(pSat, Lits, Lits + 2)) { - sat_solver_delete( pSat ); + sat_solver_delete(pSat); return NULL; } } // add clauses for the next timeframe - for ( i = 0; i < p->nLiterals; i++ ) + for (i = 0; i < p->nLiterals; i++) pLits[i] += nLitsAll; - for ( i = 0; i < p->nClauses; i++ ) + for (i = 0; i < p->nClauses; i++) { - if ( !sat_solver_addclause( pSat, p->pClauses[i], p->pClauses[i+1] ) ) + if (!sat_solver_addclause(pSat, p->pClauses[i], p->pClauses[i + 1])) { - sat_solver_delete( pSat ); + sat_solver_delete(pSat); return NULL; } } } // return literals to their original state - nLitsAll = (f-1) * nLitsAll; - for ( i = 0; i < p->nLiterals; i++ ) + nLitsAll = (f - 1) * nLitsAll; + for (i = 0; i < p->nLiterals; i++) pLits[i] -= nLitsAll; } - if ( fInit ) + if (fInit) { - Aig_Obj_t * pObjLo; + Aig_Obj_t *pObjLo; int Lits[1]; - Aig_ManForEachLoSeq( p->pMan, pObjLo, i ) + Aig_ManForEachLoSeq(p->pMan, pObjLo, i) { - Lits[0] = toLitCond( p->pVarNums[pObjLo->Id], 1 ); - if ( !sat_solver_addclause( pSat, Lits, Lits + 1 ) ) + Lits[0] = toLitCond(p->pVarNums[pObjLo->Id], 1); + if (!sat_solver_addclause(pSat, Lits, Lits + 1)) { - sat_solver_delete( pSat ); + sat_solver_delete(pSat); return NULL; } } } status = sat_solver_simplify(pSat); - if ( status == 0 ) + if (status == 0) { - sat_solver_delete( pSat ); + sat_solver_delete(pSat); return NULL; } return pSat; @@ -570,15 +608,15 @@ void * Cnf_DataWriteIntoSolverInt( void * pSolver, Cnf_Dat_t * p, int nFrames, i Synopsis [Writes CNF into a file.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void * Cnf_DataWriteIntoSolver( Cnf_Dat_t * p, int nFrames, int fInit ) +void *Cnf_DataWriteIntoSolver(Cnf_Dat_t *p, int nFrames, int fInit) { - return Cnf_DataWriteIntoSolverInt( sat_solver_new(), p, nFrames, fInit ); + return Cnf_DataWriteIntoSolverInt(sat_solver_new(), p, nFrames, fInit); } /**Function************************************************************* @@ -586,88 +624,88 @@ void * Cnf_DataWriteIntoSolver( Cnf_Dat_t * p, int nFrames, int fInit ) Synopsis [Writes CNF into a file.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void * Cnf_DataWriteIntoSolver2( Cnf_Dat_t * p, int nFrames, int fInit ) +void *Cnf_DataWriteIntoSolver2(Cnf_Dat_t *p, int nFrames, int fInit) { - sat_solver2 * pSat; + sat_solver2 *pSat; int i, f, status; - assert( nFrames > 0 ); + assert(nFrames > 0); pSat = sat_solver2_new(); - sat_solver2_setnvars( pSat, p->nVars * nFrames ); - for ( i = 0; i < p->nClauses; i++ ) + sat_solver2_setnvars(pSat, p->nVars * nFrames); + for (i = 0; i < p->nClauses; i++) { - if ( !sat_solver2_addclause( pSat, p->pClauses[i], p->pClauses[i+1], 0 ) ) + if (!sat_solver2_addclause(pSat, p->pClauses[i], p->pClauses[i + 1], 0)) { - sat_solver2_delete( pSat ); + sat_solver2_delete(pSat); return NULL; } } - if ( nFrames > 1 ) + if (nFrames > 1) { - Aig_Obj_t * pObjLo, * pObjLi; - int nLitsAll, * pLits, Lits[2]; + Aig_Obj_t *pObjLo, *pObjLi; + int nLitsAll, *pLits, Lits[2]; nLitsAll = 2 * p->nVars; pLits = p->pClauses[0]; - for ( f = 1; f < nFrames; f++ ) + for (f = 1; f < nFrames; f++) { // add equality of register inputs/outputs for different timeframes - Aig_ManForEachLiLoSeq( p->pMan, pObjLi, pObjLo, i ) + Aig_ManForEachLiLoSeq(p->pMan, pObjLi, pObjLo, i) { - Lits[0] = (f-1)*nLitsAll + toLitCond( p->pVarNums[pObjLi->Id], 0 ); - Lits[1] = f *nLitsAll + toLitCond( p->pVarNums[pObjLo->Id], 1 ); - if ( !sat_solver2_addclause( pSat, Lits, Lits + 2, 0 ) ) + Lits[0] = (f - 1) * nLitsAll + toLitCond(p->pVarNums[pObjLi->Id], 0); + Lits[1] = f * nLitsAll + toLitCond(p->pVarNums[pObjLo->Id], 1); + if (!sat_solver2_addclause(pSat, Lits, Lits + 2, 0)) { - sat_solver2_delete( pSat ); + sat_solver2_delete(pSat); return NULL; } Lits[0]++; Lits[1]--; - if ( !sat_solver2_addclause( pSat, Lits, Lits + 2, 0 ) ) + if (!sat_solver2_addclause(pSat, Lits, Lits + 2, 0)) { - sat_solver2_delete( pSat ); + sat_solver2_delete(pSat); return NULL; } } // add clauses for the next timeframe - for ( i = 0; i < p->nLiterals; i++ ) + for (i = 0; i < p->nLiterals; i++) pLits[i] += nLitsAll; - for ( i = 0; i < p->nClauses; i++ ) + for (i = 0; i < p->nClauses; i++) { - if ( !sat_solver2_addclause( pSat, p->pClauses[i], p->pClauses[i+1], 0 ) ) + if (!sat_solver2_addclause(pSat, p->pClauses[i], p->pClauses[i + 1], 0)) { - sat_solver2_delete( pSat ); + sat_solver2_delete(pSat); return NULL; } } } // return literals to their original state - nLitsAll = (f-1) * nLitsAll; - for ( i = 0; i < p->nLiterals; i++ ) + nLitsAll = (f - 1) * nLitsAll; + for (i = 0; i < p->nLiterals; i++) pLits[i] -= nLitsAll; } - if ( fInit ) + if (fInit) { - Aig_Obj_t * pObjLo; + Aig_Obj_t *pObjLo; int Lits[1]; - Aig_ManForEachLoSeq( p->pMan, pObjLo, i ) + Aig_ManForEachLoSeq(p->pMan, pObjLo, i) { - Lits[0] = toLitCond( p->pVarNums[pObjLo->Id], 1 ); - if ( !sat_solver2_addclause( pSat, Lits, Lits + 1, 0 ) ) + Lits[0] = toLitCond(p->pVarNums[pObjLo->Id], 1); + if (!sat_solver2_addclause(pSat, Lits, Lits + 1, 0)) { - sat_solver2_delete( pSat ); + sat_solver2_delete(pSat); return NULL; } } } status = sat_solver2_simplify(pSat); - if ( status == 0 ) + if (status == 0) { - sat_solver2_delete( pSat ); + sat_solver2_delete(pSat); return NULL; } return pSat; @@ -678,26 +716,26 @@ void * Cnf_DataWriteIntoSolver2( Cnf_Dat_t * p, int nFrames, int fInit ) Synopsis [Adds the OR-clause.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -int Cnf_DataWriteOrClause( void * p, Cnf_Dat_t * pCnf ) +int Cnf_DataWriteOrClause(void *p, Cnf_Dat_t *pCnf) { - sat_solver * pSat = (sat_solver *)p; - Aig_Obj_t * pObj; - int i, * pLits; - pLits = ABC_ALLOC( int, Aig_ManCoNum(pCnf->pMan) ); - Aig_ManForEachCo( pCnf->pMan, pObj, i ) - pLits[i] = toLitCond( pCnf->pVarNums[pObj->Id], 0 ); - if ( !sat_solver_addclause( pSat, pLits, pLits + Aig_ManCoNum(pCnf->pMan) ) ) + sat_solver *pSat = (sat_solver *)p; + Aig_Obj_t *pObj; + int i, *pLits; + pLits = ABC_ALLOC(int, Aig_ManCoNum(pCnf->pMan)); + Aig_ManForEachCo(pCnf->pMan, pObj, i) + pLits[i] = toLitCond(pCnf->pVarNums[pObj->Id], 0); + if (!sat_solver_addclause(pSat, pLits, pLits + Aig_ManCoNum(pCnf->pMan))) { - ABC_FREE( pLits ); + ABC_FREE(pLits); return 0; } - ABC_FREE( pLits ); + ABC_FREE(pLits); return 1; } @@ -706,26 +744,26 @@ int Cnf_DataWriteOrClause( void * p, Cnf_Dat_t * pCnf ) Synopsis [Adds the OR-clause.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -int Cnf_DataWriteOrClause2( void * p, Cnf_Dat_t * pCnf ) +int Cnf_DataWriteOrClause2(void *p, Cnf_Dat_t *pCnf) { - sat_solver2 * pSat = (sat_solver2 *)p; - Aig_Obj_t * pObj; - int i, * pLits; - pLits = ABC_ALLOC( int, Aig_ManCoNum(pCnf->pMan) ); - Aig_ManForEachCo( pCnf->pMan, pObj, i ) - pLits[i] = toLitCond( pCnf->pVarNums[pObj->Id], 0 ); - if ( !sat_solver2_addclause( pSat, pLits, pLits + Aig_ManCoNum(pCnf->pMan), 0 ) ) + sat_solver2 *pSat = (sat_solver2 *)p; + Aig_Obj_t *pObj; + int i, *pLits; + pLits = ABC_ALLOC(int, Aig_ManCoNum(pCnf->pMan)); + Aig_ManForEachCo(pCnf->pMan, pObj, i) + pLits[i] = toLitCond(pCnf->pVarNums[pObj->Id], 0); + if (!sat_solver2_addclause(pSat, pLits, pLits + Aig_ManCoNum(pCnf->pMan), 0)) { - ABC_FREE( pLits ); + ABC_FREE(pLits); return 0; } - ABC_FREE( pLits ); + ABC_FREE(pLits); return 1; } @@ -734,21 +772,21 @@ int Cnf_DataWriteOrClause2( void * p, Cnf_Dat_t * pCnf ) Synopsis [Adds the OR-clause.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -int Cnf_DataWriteAndClauses( void * p, Cnf_Dat_t * pCnf ) +int Cnf_DataWriteAndClauses(void *p, Cnf_Dat_t *pCnf) { - sat_solver * pSat = (sat_solver *)p; - Aig_Obj_t * pObj; + sat_solver *pSat = (sat_solver *)p; + Aig_Obj_t *pObj; int i, Lit; - Aig_ManForEachCo( pCnf->pMan, pObj, i ) + Aig_ManForEachCo(pCnf->pMan, pObj, i) { - Lit = toLitCond( pCnf->pVarNums[pObj->Id], 0 ); - if ( !sat_solver_addclause( pSat, &Lit, &Lit+1 ) ) + Lit = toLitCond(pCnf->pVarNums[pObj->Id], 0); + if (!sat_solver_addclause(pSat, &Lit, &Lit + 1)) return 0; } return 1; @@ -759,35 +797,35 @@ int Cnf_DataWriteAndClauses( void * p, Cnf_Dat_t * pCnf ) Synopsis [Transforms polarity of the internal veriables.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -void Cnf_DataTranformPolarity( Cnf_Dat_t * pCnf, int fTransformPos ) +void Cnf_DataTranformPolarity(Cnf_Dat_t *pCnf, int fTransformPos) { - Aig_Obj_t * pObj; - int * pVarToPol; + Aig_Obj_t *pObj; + int *pVarToPol; int i, iVar; // create map from the variable number to its polarity - pVarToPol = ABC_CALLOC( int, pCnf->nVars ); - Aig_ManForEachObj( pCnf->pMan, pObj, i ) + pVarToPol = ABC_CALLOC(int, pCnf->nVars); + Aig_ManForEachObj(pCnf->pMan, pObj, i) { - if ( !fTransformPos && Aig_ObjIsCo(pObj) ) + if (!fTransformPos && Aig_ObjIsCo(pObj)) continue; - if ( pCnf->pVarNums[pObj->Id] >= 0 ) - pVarToPol[ pCnf->pVarNums[pObj->Id] ] = pObj->fPhase; + if (pCnf->pVarNums[pObj->Id] >= 0) + pVarToPol[pCnf->pVarNums[pObj->Id]] = pObj->fPhase; } // transform literals - for ( i = 0; i < pCnf->nLiterals; i++ ) + for (i = 0; i < pCnf->nLiterals; i++) { iVar = lit_var(pCnf->pClauses[0][i]); - assert( iVar < pCnf->nVars ); - if ( pVarToPol[iVar] ) - pCnf->pClauses[0][i] = lit_neg( pCnf->pClauses[0][i] ); + assert(iVar < pCnf->nVars); + if (pVarToPol[iVar]) + pCnf->pClauses[0][i] = lit_neg(pCnf->pClauses[0][i]); } - ABC_FREE( pVarToPol ); + ABC_FREE(pVarToPol); } /**Function************************************************************* @@ -795,39 +833,39 @@ void Cnf_DataTranformPolarity( Cnf_Dat_t * pCnf, int fTransformPos ) Synopsis [Adds constraints for the two-input AND-gate.] Description [] - + SideEffects [] SeeAlso [] ***********************************************************************/ -int Cnf_DataAddXorClause( void * pSat, int iVarA, int iVarB, int iVarC ) +int Cnf_DataAddXorClause(void *pSat, int iVarA, int iVarB, int iVarC) { lit Lits[3]; - assert( iVarA > 0 && iVarB > 0 && iVarC > 0 ); + assert(iVarA > 0 && iVarB > 0 && iVarC > 0); - Lits[0] = toLitCond( iVarA, 1 ); - Lits[1] = toLitCond( iVarB, 1 ); - Lits[2] = toLitCond( iVarC, 1 ); - if ( !sat_solver_addclause( (sat_solver *)pSat, Lits, Lits + 3 ) ) + Lits[0] = toLitCond(iVarA, 1); + Lits[1] = toLitCond(iVarB, 1); + Lits[2] = toLitCond(iVarC, 1); + if (!sat_solver_addclause((sat_solver *)pSat, Lits, Lits + 3)) return 0; - Lits[0] = toLitCond( iVarA, 1 ); - Lits[1] = toLitCond( iVarB, 0 ); - Lits[2] = toLitCond( iVarC, 0 ); - if ( !sat_solver_addclause( (sat_solver *)pSat, Lits, Lits + 3 ) ) + Lits[0] = toLitCond(iVarA, 1); + Lits[1] = toLitCond(iVarB, 0); + Lits[2] = toLitCond(iVarC, 0); + if (!sat_solver_addclause((sat_solver *)pSat, Lits, Lits + 3)) return 0; - Lits[0] = toLitCond( iVarA, 0 ); - Lits[1] = toLitCond( iVarB, 1 ); - Lits[2] = toLitCond( iVarC, 0 ); - if ( !sat_solver_addclause( (sat_solver *)pSat, Lits, Lits + 3 ) ) + Lits[0] = toLitCond(iVarA, 0); + Lits[1] = toLitCond(iVarB, 1); + Lits[2] = toLitCond(iVarC, 0); + if (!sat_solver_addclause((sat_solver *)pSat, Lits, Lits + 3)) return 0; - Lits[0] = toLitCond( iVarA, 0 ); - Lits[1] = toLitCond( iVarB, 0 ); - Lits[2] = toLitCond( iVarC, 1 ); - if ( !sat_solver_addclause( (sat_solver *)pSat, Lits, Lits + 3 ) ) + Lits[0] = toLitCond(iVarA, 0); + Lits[1] = toLitCond(iVarB, 0); + Lits[2] = toLitCond(iVarC, 1); + if (!sat_solver_addclause((sat_solver *)pSat, Lits, Lits + 3)) return 0; return 1; @@ -837,6 +875,4 @@ int Cnf_DataAddXorClause( void * pSat, int iVarA, int iVarB, int iVarC ) /// END OF FILE /// //////////////////////////////////////////////////////////////////////// - ABC_NAMESPACE_IMPL_END - diff --git a/src/sat/glucose/AbcGlucose.cpp b/src/sat/glucose/AbcGlucose.cpp index d6f4c454d..3df050cbc 100644 --- a/src/sat/glucose/AbcGlucose.cpp +++ b/src/sat/glucose/AbcGlucose.cpp @@ -878,6 +878,9 @@ Vec_Int_t * Glucose_SolverFromAig( Gia_Man_t * p, SimpSolver& s ) abctime clk = Abc_Clock(); vec * lits = &s.user_lits; Cnf_Dat_t * pCnf = (Cnf_Dat_t *)Mf_ManGenerateCnf( p, 8 /*nLutSize*/, 0 /*fCnfObjIds*/, 1/*fAddOrCla*/, 0, 0/*verbose*/ ); + // CNF variable IDs are 1-based and may include unused variables. + // Create the full range so model[] can be indexed by pVarNums directly. + s.addVar( pCnf->nVars - 1 ); for ( int i = 0; i < pCnf->nClauses; i++ ) { lits->clear(); diff --git a/src/sat/glucose2/AbcGlucose2.cpp b/src/sat/glucose2/AbcGlucose2.cpp index 6201779cb..2d7d1c3f5 100644 --- a/src/sat/glucose2/AbcGlucose2.cpp +++ b/src/sat/glucose2/AbcGlucose2.cpp @@ -896,6 +896,9 @@ Vec_Int_t * Glucose_SolverFromAig( Gia_Man_t * p, SimpSolver& s ) abctime clk = Abc_Clock(); vec * lits = &s.user_lits; Cnf_Dat_t * pCnf = (Cnf_Dat_t *)Mf_ManGenerateCnf( p, 8 /*nLutSize*/, 0 /*fCnfObjIds*/, 1/*fAddOrCla*/, 0, 0/*verbose*/ ); + // CNF variable IDs are 1-based and may include unused variables. + // Create the full range so model[] can be indexed by pVarNums directly. + s.addVar( pCnf->nVars - 1 ); for ( int i = 0; i < pCnf->nClauses; i++ ) { lits->clear(); diff --git a/test/write_cnf_dangling.sh b/test/write_cnf_dangling.sh new file mode 100755 index 000000000..bbb80b7dc --- /dev/null +++ b/test/write_cnf_dangling.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# Regression test for berkeley-abc/abc#479 +# +# After "strash", a primary input wired directly to a primary output becomes +# a dangling PI: it shows up in the DIMACS header's variable count but the +# Tseitin encoder emits no clause mentioning it. Such a free variable +# silently doubles the model count of the written formula, breaking #SAT +# and uniform sampling. +# +# The fix in Cnf_DataWriteIntoFile() detects DIMACS variables that are +# declared in the header but unreferenced in any clause, and emits a unit +# clause pinning each of them to false. The two cases below exercise that +# behaviour against the abc binary. + +set -eu + +ABC=${ABC:-./abc} +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT + +fail() { echo "FAIL: $1" >&2; exit 1; } + +run_case() { + local name=$1 input=$2 + local in="$TMP/$name.in.cnf" out="$TMP/$name.out.cnf" + printf '%s' "$input" > "$in" + "$ABC" -q "read_cnf $in; strash; write_cnf $out" > /dev/null + + # Extract declared variable count from the header. + local header + header=$(grep -m1 '^p cnf ' "$out") + local nVars + nVars=$(echo "$header" | awk '{print $3}') + + # Every variable 1..nVars must appear (positive or negated) in some clause. + local v + for v in $(seq 1 "$nVars"); do + if ! grep -Eq "(^|[ \t-])$v( |$)" "$out"; then + cat "$out" >&2 + fail "$name: variable $v declared in header but never used in any clause" + fi + done + echo "PASS: $name ($header)" +} + +# Case 1: original reproducer from issue #479 -- a single PI wired directly +# to a single PO. Before the fix, the output was "p cnf 3 2" with clauses +# "-3 0" and "2 0", leaving variable 1 unconstrained. +run_case "pi_to_po_direct" "p cnf 1 1 +1 0 +" + +# Case 2: two independent PIs, each a direct wire to its own PO. Both PIs +# end up dangling after strash. +run_case "two_pis_two_pos" "p cnf 2 2 +1 0 +2 0 +" + +echo "All regression tests passed."