From fa042e42ed8b5c0a6abcd072d4ae5bd44ee4d922 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Sat, 18 Apr 2026 10:25:11 +0200 Subject: [PATCH 01/25] Corrected #ifdef for mach based Apple builds in cadical_file.cpp. Bring test in line with all other tests for mach based MacOS builds, and ensure the code in question is not enabled with mach on GNU Hurd. --- src/sat/cadical/cadical_file.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 } From 1ddb7a2352c9272c64ee65dfe80c5d57d95d8266 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Sun, 19 Apr 2026 07:20:00 +0200 Subject: [PATCH 02/25] Provide replacement value for PATH_MAX on platforms without it. The buffer length is used in a static array returned from Extra_FileNameGenericAppend(), used many places in the code, and a more dynamic approach would require a huge refactoring. There is no guarantee that the 4096 value picked is large enough, but it matches common values found on Linux. --- src/misc/extra/extraUtilFile.c | 3 +++ 1 file changed, 3 insertions(+) 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" From 2b9920e6a5f246ae7c7d2e3d1c77e60665eb9763 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Thu, 23 Apr 2026 07:31:33 +0200 Subject: [PATCH 03/25] Relaxed assert in Io_WritePla() to avoid failure with too shallow network. Otherwise the abc will refuse to output trivial functions(constant 1 or 0). The issue was originally submitted to , now available via . Sadly the example demonstrated the problem was not archived. This issue was also reported as . --- src/base/io/ioWritePla.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ) From 817d542c45fa92ac8367b15fd3f7b00f43ee8113 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Thu, 23 Apr 2026 14:52:54 +0200 Subject: [PATCH 04/25] Use CPPFLAGS alongside CFLAGS and CXXFLAGS during build. It is a convention inherited from GNU automake to use CPPFLAGS for compiler flag intended for the preprocessor, while CFLAGS and and CXXFLAGS provide flags intended for the C and C++ compiler. Adjust build rules to include CPPFLAGS ensure any preprocessor flags in build systems using this environment variable work out of the box. This allow Debian builds to pass on hardening flags without modifying the build setup. Patch from Ruben Undheim via Debian --- Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index eeff20d24..adb8ee302 100644 --- a/Makefile +++ b/Makefile @@ -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) From d74b33eba6fe84794ee11abb011728d0f754cc40 Mon Sep 17 00:00:00 2001 From: Advay Singh Date: Thu, 23 Apr 2026 13:09:26 -0500 Subject: [PATCH 05/25] Added fix for write_cnf adding extra clauses on direct PI-PO --- src/sat/cnf/cnfMan.c | 734 +++++++++++++++++++------------------ test/write_cnf_dangling.sh | 60 +++ 2 files changed, 445 insertions(+), 349 deletions(-) create mode 100755 test/write_cnf_dangling.sh 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/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." From 1056de32396b7655caedc7bb0f3c94f0a00fcf9f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 24 Apr 2026 18:57:29 -0700 Subject: [PATCH 06/25] High memory use fix in &scorr -Z --- src/proof/cec/cecCorr.c | 131 +++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 29 deletions(-) diff --git a/src/proof/cec/cecCorr.c b/src/proof/cec/cecCorr.c index 0496b2e49..be0b08ba5 100644 --- a/src/proof/cec/cecCorr.c +++ b/src/proof/cec/cecCorr.c @@ -762,6 +762,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 ) { @@ -994,6 +995,7 @@ 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; } @@ -1009,6 +1011,7 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) { Cec_ManSimStop( pSim ); Abc_Print( 1, "Stopped signal correspondence after %d refiment iterations.\n", r ); + fflush( stdout ); return 1; } clk = Abc_Clock(); @@ -1062,6 +1065,7 @@ 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 ); return 0; } @@ -1072,6 +1076,7 @@ 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 ); ABC_FREE( pAig->pReprs ); ABC_FREE( pAig->pNexts ); @@ -1101,6 +1106,7 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) ABC_PRTP( "Sim ", clkSim, clkTotal ); ABC_PRTP( "Other", clkTotal-clkSat-clkSrm-clkSim, clkTotal ); Abc_PrintTime( 1, "TOTAL", clkTotal ); + fflush( stdout ); } return 1; } @@ -1299,42 +1305,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 +1437,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 ) From 8e6b28767476cb1226c9af871eebc78bd0fcbfa4 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 25 Apr 2026 17:42:06 -0700 Subject: [PATCH 07/25] Improving callbacks in &bmcG --- src/sat/bmc/bmcBmcG.c | 8 ++++++++ 1 file changed, 8 insertions(+) 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 ) From c20832627f3b70f545b16d27a54d1e58fd3a8535 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 25 Apr 2026 17:45:55 -0700 Subject: [PATCH 08/25] Extending &sprove interface --- src/base/abci/abc.c | 29 ++- src/opt/ufar/UfarCmd.cpp | 518 ++++++++++++++++++++++++++++----------- src/opt/ufar/UfarCmd.h | 2 +- src/opt/untk/NtkNtk.cpp | 24 +- src/proof/cec/cecProve.c | 71 +++++- 5 files changed, 474 insertions(+), 170 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 998b3e16b..691842fc8 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -686,7 +686,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 ); @@ -51559,10 +51559,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; 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 ) { @@ -51599,7 +51599,16 @@ 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; + } + pUfarArgs = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'W': if ( globalUtilOptind >= argc ) { @@ -51662,6 +51671,11 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) Gia_ManStop( pGiaTemp ); pGiaTemp = NULL; } + else if ( pUfarArgs != NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9SProve(): Option \"-C\" requires \"-u\".\n" ); + return 1; + } if ( pGiaUse == NULL ) { Abc_Print( -1, "Abc_CommandAbc9SProve(): There is no AIG.\n" ); @@ -51674,18 +51688,19 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) Gia_ManStop( pGiaUse ); 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 ); 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" ); diff --git a/src/opt/ufar/UfarCmd.cpp b/src/opt/ufar/UfarCmd.cpp index f4bd70b20..50b631a54 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,14 @@ 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; +static __thread Ufar_StopCtx_t g_UfarStopCtx = { NULL, 0, 0, {0, 0} }; 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 +49,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 +115,194 @@ 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; +} + void Ufar_Init(Abc_Frame_t *pAbc) { @@ -84,39 +313,163 @@ 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 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 ) + OptMgr opt_mgr("%ufar"); + Ufar_AddOptions( opt_mgr, manager.params ); + if ( !Ufar_TokenizeArgs(pArgs, 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 ); + } + 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 +513,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 +538,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 +552,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 +614,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 b0cb5bd15..2e6782731 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; int res = system( command.c_str() ); diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index 8b7aa2868..43395aa23 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -61,15 +61,15 @@ struct Cec_SproveTrace_t_; 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 ); -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 ); 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; } @@ -104,6 +104,7 @@ typedef struct Par_ThData_t_ int fVerbose; int nTimeOutU; Wlc_Ntk_t * pWlc; + const char * pUfarArgs; int WorkerId; int StageId; int NetId; @@ -152,6 +153,7 @@ struct Cec_SprovePlan_t_ int nTimeOut2; int nTimeOut3; int fUseUif; + char * pUfarArgs; int nStages; Cec_SproveStage_t Stages[SPROVE_STAGE_MAX]; }; @@ -309,6 +311,13 @@ static void Cec_SproveDeriveEngineList( int nProcs, int fUseUif, int * pEngines, { int i, nEngines = nProcs + (fUseUif ? 1 : 0); assert( nEngines >= 1 && nEngines <= PAR_THR_MAX ); + if ( fUseUif && nProcs == 6 ) + { + 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 ) @@ -320,7 +329,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) ); @@ -334,6 +361,7 @@ static void Cec_SprovePlanDefault( Cec_SprovePlan_t * pPlan, int nProcs, int nTi pPlan->nTimeOut2 = nTimeOut2; pPlan->nTimeOut3 = nTimeOut3; pPlan->fUseUif = fUseUif; + Cec_SprovePlanSetUfarArgs( pPlan, pUfarArgs ); pPlan->nStages = 4; Cec_SproveDeriveEngineList( nProcs, fUseUif, pPlan->Stages[0].RoundEngines, &nEngines ); @@ -408,6 +436,8 @@ 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->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++ ) @@ -479,12 +509,20 @@ 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 ( pPlan->nProcs > 0 && (strncmp(Buffer, "PLAN_BEGIN", 10) == 0 || strncmp(Buffer, "OBSERVED_BEGIN", 14) == 0) ) + { fclose( pFile ); return 1; } } fclose( pFile ); - return 0; + return pPlan->nProcs > 0; } static int Cec_SproveReplayReadPlan( char * pFileName, Cec_SprovePlan_t * pPlan ) { @@ -717,7 +755,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; } @@ -918,7 +956,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; } } @@ -1070,7 +1108,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 ); @@ -1088,6 +1126,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; @@ -1115,6 +1154,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; @@ -1188,22 +1228,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 From b2a0cabf297d871d723e67b1e4276fe24d1017fb Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 25 Apr 2026 22:32:27 -0700 Subject: [PATCH 09/25] Updates to &sprove. --- src/proof/cec/cecProve.c | 90 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 9 deletions(-) diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index 43395aa23..f9a6de09b 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -153,6 +153,8 @@ 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,20 +309,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 ) { - int UifEngines[7] = { 0, 1, 2, 3, 4, PAR_ENGINE_GLA, PAR_ENGINE_UFAR }; - memcpy( pEngines, UifEngines, sizeof(UifEngines) ); - *pnEngines = 7; + 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; @@ -361,9 +384,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; @@ -402,6 +426,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, ... ) { @@ -436,6 +461,8 @@ 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, "" ); @@ -515,8 +542,17 @@ static int Cec_SproveReplayReadParamsInt( char * pFileName, Cec_SprovePlan_t * p 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; } @@ -714,20 +750,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 ) @@ -736,10 +787,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 ); @@ -768,11 +828,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) ) ); @@ -788,8 +850,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 ) From b413eb90decdb07fd63e285fcb796b99c90d314a Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 25 Apr 2026 22:41:26 -0700 Subject: [PATCH 10/25] Fix windows build. --- src/opt/ufar/UfarCmd.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/opt/ufar/UfarCmd.cpp b/src/opt/ufar/UfarCmd.cpp index 50b631a54..c3f64d2b1 100755 --- a/src/opt/ufar/UfarCmd.cpp +++ b/src/opt/ufar/UfarCmd.cpp @@ -38,7 +38,15 @@ typedef struct Ufar_StopCtx_t_ 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 ); From 153d6b7f823bea309f97742d820e26b007660ae9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 30 Apr 2026 18:04:04 -0700 Subject: [PATCH 11/25] Fix out-of-bound bug in &glucose --- src/sat/glucose/AbcGlucose.cpp | 3 +++ src/sat/glucose2/AbcGlucose2.cpp | 3 +++ 2 files changed, 6 insertions(+) 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(); From d07ce81c91b3ce92d848241f5db8e7438e22625e Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 30 Apr 2026 23:38:51 -0700 Subject: [PATCH 12/25] Bug fixes. --- src/opt/fret/fretMain.c | 4 ++-- src/opt/fret/fretTime.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) 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) { From 60e091d993e2c44c5693cedfeffbf47428aaf823 Mon Sep 17 00:00:00 2001 From: Fred Tombs Date: Sat, 2 May 2026 10:09:50 -0400 Subject: [PATCH 13/25] Replace failing assert in lutpack with non-failing version --- src/opt/lpk/lpkCut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/lpk/lpkCut.c b/src/opt/lpk/lpkCut.c index 41cfaed5f..12dfc4ae8 100644 --- a/src/opt/lpk/lpkCut.c +++ b/src/opt/lpk/lpkCut.c @@ -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 From ff00f67063ad9a1ffae5db5bc05060980c334bd6 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 2 May 2026 08:22:59 -0700 Subject: [PATCH 14/25] Updating verilog writer. --- src/base/abc/abcHieGia.c | 318 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) diff --git a/src/base/abc/abcHieGia.c b/src/base/abc/abcHieGia.c index ea3c2d09a..726ee07bc 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,85 @@ 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 fFirst = 0; + 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 +1310,214 @@ 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 ) +{ + Gia_Obj_t * pObj, * pObjRi, * pObjRo; + int nDigits = Abc_Base10Log( Gia_ManObjNum(p) ); + int nPerLine = 4, nOnLine = 0; + int i; + FILE * pFile; + 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 ); + 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 clk) 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************************************************************* @@ -1224,6 +1537,11 @@ static void GiaHie_DumpInterfaceAssigns( Gia_Man_t * p, char * pFileName ) int nPerLine = 4; int nOnLine = 0; int i; + if ( Gia_ManRegNum(p) > 0 ) + { + GiaHie_DumpInterfaceAssignsSeq( p, pFileName ); + return; + } FILE * pFile = fopen( pFileName, "wb" ); if ( pFile == NULL ) { From db8e5d9988cf4a55ada9003d1af020b76f22eb2f Mon Sep 17 00:00:00 2001 From: Fred Tombs Date: Sat, 2 May 2026 16:15:00 -0400 Subject: [PATCH 15/25] Apply same assert fix to l144 --- src/opt/lpk/lpkCut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/lpk/lpkCut.c b/src/opt/lpk/lpkCut.c index 12dfc4ae8..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 From fc4cfc0c35c88d6455729164800bdb51efd28d09 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 4 May 2026 18:56:14 -0700 Subject: [PATCH 16/25] Extending support for sequential AIGs. --- src/aig/gia/giaAiger.c | 5 +- src/aig/gia/giaDup.c | 585 +++++++++++++++++++++++++++++++++++++++ src/base/abc/abcHieGia.c | 40 ++- src/base/abci/abc.c | 226 ++++++++++++++- 4 files changed, 837 insertions(+), 19 deletions(-) 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..c98a23c85 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, 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 ); + nStageMax = Gia_ManLevelNum( p ) / nLevels; + 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) / 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 ) + { + iStage = Vec_IntEntry( vStages, Gia_ObjFaninId0p(p, pObj) ); + iLit = Gia_ManDupPipelineDelayLit( pNew, vLitMap, vStages, vRegDrivers, vRegStages, nStageCols, Gia_ObjFaninId0p(p, pObj), iStage ); + 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/base/abc/abcHieGia.c b/src/base/abc/abcHieGia.c index 726ee07bc..bb35e7f0e 100644 --- a/src/base/abc/abcHieGia.c +++ b/src/base/abc/abcHieGia.c @@ -1110,11 +1110,14 @@ static void GiaHie_DumpPortDeclsOneSome( Vec_Ptr_t * vNames, int nBits, FILE * p Vec_IntFree( vArray ); } } -static void GiaHie_DumpPortDeclsSeq( Gia_Man_t * p, FILE * pFile ) +static void GiaHie_DumpPortDeclsSeq( Gia_Man_t * p, FILE * pFile, int fUseCtrlPis ) { - int fFirst = 0; - fprintf( pFile, " input clk,\n" ); - fprintf( pFile, " input rst" ); + 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 ); } @@ -1434,13 +1437,18 @@ static void GiaHie_DumpOutputAssignsSome( Gia_Man_t * p, FILE * pFile, int nDigi Vec_IntFree( vArray ); } } -static void GiaHie_DumpInterfaceAssignsSeq( Gia_Man_t * p, char * pFileName ) +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 ) { @@ -1451,7 +1459,7 @@ static void GiaHie_DumpInterfaceAssignsSeq( Gia_Man_t * p, char * pFileName ) fprintf( pFile, "module " ); GiaHie_DumpModuleName( pFile, p->pName ); fprintf( pFile, " (\n" ); - GiaHie_DumpPortDeclsSeq( p, pFile ); + GiaHie_DumpPortDeclsSeq( p, pFile, fUseCtrlPis ); fprintf( pFile, "\n);\n\n" ); if ( Gia_ManPiNum(p) ) @@ -1511,7 +1519,12 @@ static void GiaHie_DumpInterfaceAssignsSeq( Gia_Man_t * p, char * pFileName ) GiaHie_DumpOutputAssignsSome( p, pFile, nDigits, Gia_ManPoNum(p) ); fprintf( pFile, "\n" ); - fprintf( pFile, " always @(posedge clk) begin\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" ); @@ -1530,7 +1543,7 @@ static void GiaHie_DumpInterfaceAssignsSeq( Gia_Man_t * p, char * pFileName ) 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) ); @@ -1539,7 +1552,7 @@ static void GiaHie_DumpInterfaceAssigns( Gia_Man_t * p, char * pFileName ) int i; if ( Gia_ManRegNum(p) > 0 ) { - GiaHie_DumpInterfaceAssignsSeq( p, pFileName ); + GiaHie_DumpInterfaceAssignsSeq( p, pFileName, fUseCtrlPis ); return; } FILE * pFile = fopen( pFileName, "wb" ); @@ -1812,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 ) @@ -1820,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/abci/abc.c b/src/base/abci/abc.c index 691842fc8..7b760ceb1 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -661,6 +661,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 ); @@ -1514,6 +1517,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 ); @@ -35140,18 +35146,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 ) { @@ -35164,6 +35171,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; @@ -35207,7 +35217,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 @@ -35230,9 +35240,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" ); @@ -59869,6 +59880,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 [] From eaa8496b4253ad0ba2610f155cc8a30d2a87c9c9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 8 May 2026 00:45:46 -0700 Subject: [PATCH 17/25] Streamlining support for multi-output gates --- src/base/io/ioJsonc.c | 141 +++++++++++++++++++++++++++++++++-- src/base/io/ioReadBlif.c | 78 +++++++++++-------- src/base/io/ioWriteBlif.c | 14 +++- src/base/io/ioWriteVerilog.c | 63 +++++++++++++++- src/map/scl/sclLib.h | 9 ++- src/map/scl/sclSize.c | 52 ++++++++++++- 6 files changed, 314 insertions(+), 43 deletions(-) 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/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/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 - From f3157272ae94a067f8a41b92b890061c77e7a91a Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 8 May 2026 16:03:24 -0700 Subject: [PATCH 18/25] Initial support of multi-output gates in sizing. --- src/base/abc/abcNtk.c | 82 ++++++++++++++++++++++++++++++++++++++++- src/map/scl/sclDnsize.c | 3 +- src/map/scl/sclSize.h | 63 +++++++++++++++++++++++++++++++ src/map/scl/sclUpsize.c | 7 ++-- src/map/scl/sclUtil.c | 5 ++- 5 files changed, 151 insertions(+), 9 deletions(-) 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/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/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 - From cf5da03652bac96a2453f0887d47040f1ae6aa10 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 9 May 2026 19:13:42 -0700 Subject: [PATCH 19/25] Bug fix. --- src/aig/gia/giaDup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/aig/gia/giaDup.c b/src/aig/gia/giaDup.c index c98a23c85..a29271605 100644 --- a/src/aig/gia/giaDup.c +++ b/src/aig/gia/giaDup.c @@ -7035,7 +7035,7 @@ Gia_Man_t * Gia_ManDupPipeline( Gia_Man_t * p, int nLevels, int fVerbose ) Vec_Int_t * vStages, * vLitMap, * vRegDrivers, * vRegStages, * vStageCounts; Vec_Ptr_t * vNamesIn, * vNamesOut; char * pNameRo; - int nObjs, nStageMax, nStageCols, i, iStage, iLit0, iLit1, iLit, iFlop; + int nObjs, nLevelMax, nStageMax, nStageCols, i, iStage, iLit0, iLit1, iLit, iFlop; if ( nLevels <= 0 ) return NULL; @@ -7044,7 +7044,8 @@ Gia_Man_t * Gia_ManDupPipeline( Gia_Man_t * p, int nLevels, int fVerbose ) Gia_ManLevelNum( p ); nObjs = Gia_ManObjNum( p ); - nStageMax = Gia_ManLevelNum( p ) / nLevels; + nLevelMax = Gia_ManLevelNum( p ); + nStageMax = nLevelMax ? (nLevelMax - 1) / nLevels : 0; nStageCols = nStageMax + 1; vStages = Vec_IntStart( nObjs ); @@ -7053,7 +7054,7 @@ Gia_Man_t * Gia_ManDupPipeline( Gia_Man_t * p, int nLevels, int fVerbose ) vRegStages = Vec_IntAlloc( 1000 ); Gia_ManForEachAnd( p, pObj, i ) - Vec_IntWriteEntry( vStages, Gia_ObjId(p, pObj), Gia_ObjLevel(p, pObj) / nLevels ); + 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 ); @@ -7078,8 +7079,7 @@ Gia_Man_t * Gia_ManDupPipeline( Gia_Man_t * p, int nLevels, int fVerbose ) Gia_ManForEachPo( p, pObj, i ) { - iStage = Vec_IntEntry( vStages, Gia_ObjFaninId0p(p, pObj) ); - iLit = Gia_ManDupPipelineDelayLit( pNew, vLitMap, vStages, vRegDrivers, vRegStages, nStageCols, Gia_ObjFaninId0p(p, pObj), iStage ); + iLit = Gia_ManDupPipelineDelayLit( pNew, vLitMap, vStages, vRegDrivers, vRegStages, nStageCols, Gia_ObjFaninId0p(p, pObj), nStageMax ); Gia_ManAppendCo( pNew, Abc_LitNotCond(iLit, Gia_ObjFaninC0(pObj)) ); } From d54cbda229b1de8c36682b482ad299a01824771a Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 10 May 2026 09:52:16 -0700 Subject: [PATCH 20/25] Multi-output gate mapper. --- Makefile | 2 +- abclib.dsp | 16 + src/base/main/mainInit.c | 4 + src/map/emap/emap.c | 158 +++ src/map/emap/emap.h | 31 + src/map/emap/emapCore.c | 2662 ++++++++++++++++++++++++++++++++++++++ src/map/emap/module.make | 2 + 7 files changed, 2874 insertions(+), 1 deletion(-) create mode 100644 src/map/emap/emap.c create mode 100644 src/map/emap/emap.h create mode 100644 src/map/emap/emapCore.c create mode 100644 src/map/emap/module.make diff --git a/Makefile b/Makefile index adb8ee302..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 \ diff --git a/abclib.dsp b/abclib.dsp index d272b819e..f1d622d2b 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" 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 From d55ae1421c7ba4f8b4f936563041fe771454c73a Mon Sep 17 00:00:00 2001 From: xiran Date: Sun, 10 May 2026 12:21:02 -0700 Subject: [PATCH 21/25] New feature: Add incremental refinement to &scorr command --- src/base/abci/abc.c | 8 +- src/proof/cec/cec.h | 1 + src/proof/cec/cecCorr.c | 101 +++++- src/proof/cec/cecCorrIncr.c | 674 ++++++++++++++++++++++++++++++++++++ src/proof/cec/cecInt.h | 33 +- src/proof/cec/module.make | 1 + 6 files changed, 805 insertions(+), 13 deletions(-) create mode 100644 src/proof/cec/cecCorrIncr.c diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 7b760ceb1..682ca67a6 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -41167,7 +41167,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 ) { @@ -41266,6 +41266,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; @@ -41339,7 +41342,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 ); @@ -41354,6 +41357,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" ); 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 be0b08ba5..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) ) { @@ -792,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; @@ -801,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; @@ -813,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 ); @@ -849,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 ); } @@ -949,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" ); @@ -999,25 +1031,65 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) 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 ) @@ -1058,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 @@ -1067,6 +1140,7 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) 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 ) @@ -1078,6 +1152,7 @@ int Cec_ManLSCorrespondenceClasses( Gia_Man_t * pAig, Cec_ParCor_t * pPars ) 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; @@ -1105,11 +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************************************************************* 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/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 \ From 60b3991a0e49f425cbc0f17e135b1a4d37beb6e2 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 11 May 2026 12:18:15 -0700 Subject: [PATCH 22/25] Assume minimum required times when not given by the user. --- src/aig/gia/giaIf.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 ); From 8c9e66205e9ae7e05e48e723132270fbb0564fef Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 11 May 2026 13:49:26 -0700 Subject: [PATCH 23/25] Bug fix in &sprove. --- src/proof/abs/absGla.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 ); From 97b15a29a067065bc6803739c2a4f0bf4a6879cb Mon Sep 17 00:00:00 2001 From: xiran Date: Mon, 11 May 2026 14:02:23 -0700 Subject: [PATCH 24/25] Fix: fix the build bug in abclib.dsp by registering cecCorrIncr.c --- abclib.dsp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/abclib.dsp b/abclib.dsp index f1d622d2b..2f16e849e 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -6681,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 From c61f1a04e9db42db9cea876c1127bfd8f3eab040 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 11 May 2026 19:27:06 -0700 Subject: [PATCH 25/25] Bug fix in handling ufar calls. --- src/base/abci/abc.c | 28 +++++++++-- src/opt/ufar/UfarCmd.cpp | 106 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 682ca67a6..f74581834 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -51574,7 +51574,7 @@ 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, * pUfarArgs = 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, "PTUCWRusvwh" ) ) != EOF ) @@ -51621,8 +51621,22 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Command line switch \"-C\" should be followed by a string.\n" ); goto usage; } - pUfarArgs = argv[globalUtilOptind]; - globalUtilOptind++; + { + 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 ) @@ -51668,18 +51682,21 @@ 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 ); @@ -51689,11 +51706,13 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) 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 ) @@ -51701,12 +51720,14 @@ 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, pUfarArgs ); Abc_FrameReplaceCex( pAbc, &pGiaUse->pCexSeq ); if ( fUseUif ) Gia_ManStop( pGiaUse ); + ABC_FREE( pUfarArgsAlloc ); return 0; usage: @@ -51723,6 +51744,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; } diff --git a/src/opt/ufar/UfarCmd.cpp b/src/opt/ufar/UfarCmd.cpp index c3f64d2b1..6270cbb59 100755 --- a/src/opt/ufar/UfarCmd.cpp +++ b/src/opt/ufar/UfarCmd.cpp @@ -311,6 +311,104 @@ static bool Ufar_TokenizeArgs( const char * pArgs, vector & Tokens ) 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) { @@ -328,6 +426,7 @@ int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*p vector Tokens; vector Argv; set set_op_types; + string ArgsWithoutSolver, SolverArg; string firstAigDumpFile, dumpLogFile; string statusName; int fNeedMiter = 1, fCrossStats = 0, UnderSize = -1; @@ -338,9 +437,12 @@ int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*p Ufar_SetDefaultParams( manager.params, nTimeOut, fVerbose, pFuncStop, RunId ); if ( pArgs && pArgs[0] ) { + 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(pArgs, Tokens) ) + if ( !Ufar_TokenizeArgs(pParseArgs, Tokens) ) { cout << "Cannot parse internal %ufar option string." << endl; return -1; @@ -355,6 +457,8 @@ int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*p 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 );