From 0fab82384ae80105885c7adedfd5c6f675c5cce8 Mon Sep 17 00:00:00 2001 From: lyj1201 <1609595919@qq.com> Date: Mon, 14 Aug 2023 12:04:33 -0600 Subject: [PATCH 01/67] add AIG random synthesis based RTL argumentation; command = aigarg --- src/base/abci/abc.c | 167 ++++++++++++++++ src/base/abci/abcOrchestration.c | 321 ++++++++++++++++++++++++++++++- 2 files changed, 484 insertions(+), 4 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 0ff8a6f34b..6e99d74810 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -164,6 +164,7 @@ static int Abc_CommandAllExact ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandTestExact ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandMajGen ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandOrchestrate ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAIGArgumentation ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandLogic ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandComb ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -917,6 +918,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Synthesis", "faultclasses", Abc_CommandFaultClasses, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "exact", Abc_CommandExact, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "orchestrate", Abc_CommandOrchestrate, 1 ); + Cmd_CommandAdd( pAbc, "Synthesis", "aigarg", Abc_CommandAIGArgumentation, 1 ); Cmd_CommandAdd( pAbc, "Exact synthesis", "bms_start", Abc_CommandBmsStart, 0 ); Cmd_CommandAdd( pAbc, "Exact synthesis", "bms_stop", Abc_CommandBmsStop, 0 ); @@ -7534,6 +7536,171 @@ int Abc_CommandOrchestrate( Abc_Frame_t * pAbc, int argc, char ** argv ) } +/**Function************************************************************* + + Synopsis [] + + Description [AIG RTL Argumentation] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAIGArgumentation( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc), * pDup; + int c, RetValue; + int nNodeSizeMax; + int nConeSizeMax; + int fUpdateLevel; + int fUseZeros_rwr; + int fUseZeros_ref; + int fUseDcs; + int fVerbose; + int RS_CUT_MIN = 4; + int RS_CUT_MAX = 16; + + int fPrecompute; + int fPlaceEnable; + int nNodesMax; + int nCutsMax; + int nLevelsOdc; + int fVeryVerbose; + int Rand_Seed; + //int sOpsOrder; + size_t NtkSize; + char *DecisionFile; + //FILE *maskFile; + extern void Rwr_Precompute(); + extern int Abc_NtkOrchRand( Abc_Ntk_t * pNtk, Vec_Int_t **pGain_rwr, Vec_Int_t **pGain_res,Vec_Int_t **pGain_ref, Vec_Int_t **DecisionMask, char *DecisionFile, int Rand_Seed, int fUseZeros_rwr, int fUseZeros_ref, int fPlaceEnable, int nCutsMax, int nNodesMax, int nLevelsOdc, int fUpdateLevel, int fVerbose, int fVeryVerbose, int nNodeSizeMax, int nConeSizeMax, int fUseDcs ); + // set defaults + nNodeSizeMax = 10; + nConeSizeMax = 16; + fUpdateLevel = 1; + fUseZeros_rwr = 0; + fUseZeros_ref = 0; + fUseDcs = 0; + fVerbose = 0; + fVeryVerbose = 0; + fPlaceEnable = 0; + fPrecompute = 0; + nCutsMax = 8; + nNodesMax = 1; + nLevelsOdc = 0; + Rand_Seed = 1; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "zZdsh" ) ) != EOF ) + { + switch ( c ) + { + case 'h': + goto usage; + break; + case 'z': + fUseZeros_rwr ^= 1; + break; + case 'Z': + fUseZeros_ref ^= 1; + break; + case 'd': + if ( globalUtilOptind >= argc ) + { + goto usage; + } + DecisionFile = argv[globalUtilOptind]; + globalUtilOptind++; + break; + case 's': + if ( globalUtilOptind >= argc ) + { + goto usage; + } + Rand_Seed = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + } + } + if ( fPrecompute ) + { + Rwr_Precompute(); + return 0; + } + if ( pNtk == NULL ) + { + Abc_Print( -1, "Empty network.\n" ); + return 1; + } + if ( nCutsMax < RS_CUT_MIN || nCutsMax > RS_CUT_MAX ) + { + Abc_Print( -1, "Can only compute cuts for %d <= K <= %d.\n", RS_CUT_MIN, RS_CUT_MAX ); + return 1; + } + if ( !Abc_NtkIsStrash(pNtk) ) + { + Abc_Print( -1, "This command can only be applied to an AIG (run \"strash\").\n" ); + return 1; + } + if ( Abc_NtkGetChoiceNum(pNtk) ) + { + Abc_Print( -1, "AIG resynthesis cannot be applied to AIGs with choice nodes.\n" ); + return 1; + } + if ( nNodeSizeMax > 15 ) + { + Abc_Print( -1, "The cone size cannot exceed 15.\n" ); + return 1; + } + + if ( fUseDcs && nNodeSizeMax >= nConeSizeMax ) + { + Abc_Print( -1, "For don't-care to work, containing cone should be larger than collapsed node.\n" ); + return 1; + } + NtkSize = Abc_NtkObjNumMax(pNtk); + + + + Vec_Int_t *DecisionMask = Vec_IntAlloc(1); + for (int i=0; inSize, DecisionList->pArray[0]); + if ( RetValue == -1 ) + { + Abc_FrameReplaceCurrentNetwork( pAbc, pDup ); + printf( "An error occurred during computation. The original network is restored.\n" ); + } + else + { + Abc_NtkDelete( pDup ); + if ( RetValue == 0 ) + { + Abc_Print( 0, "Orchestration evaluation for RL has failed.\n" ); + return 1; + } + } + // Vec_IntPrint(pGain_rwr); + return 0; + +usage: + Abc_Print( -2, "usage: aigarg [-s ] [-d ][-zZdsh]\n" ); + Abc_Print( -2, "\t performs technology-independent AIG random synthesis (node level) for RTL argumentation\n" ); + Abc_Print( -2, "\t-z : toggle using zero-cost replacements for rwr for aigarg [default = %s]\n", fUseZeros_rwr? "yes": "no" ); + Abc_Print( -2, "\t-Z : toggle using zero-cost replacements for ref for aigarg [default = %s]\n", fUseZeros_ref? "yes": "no" ); + Abc_Print( -2, "\t-d : record random synthesis decision made during argumentation [required filename; e.g., test.csv]\n"); + Abc_Print( -2, "\t-s : set the random seed for random argumentation\n"); + Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\tExample : read i10.aig;st;aigarg -s 1 -d test.csv;write i10_arg_1.aig;cec i10.aig i10_arg_1.aig\n"); + return 1; +} diff --git a/src/base/abci/abcOrchestration.c b/src/base/abci/abcOrchestration.c index fe83891ec5..af36939dd0 100644 --- a/src/base/abci/abcOrchestration.c +++ b/src/base/abci/abcOrchestration.c @@ -198,7 +198,7 @@ Rwr_ManAddTimeCuts( pManRwr, Abc_Clock() - clk ); pManRwr->nNodesBeg = Abc_NtkNodeNum(pNtk); nNodes = Abc_NtkObjNumMax(pNtk); - printf("nNodes: %d\n", nNodes); + //printf("nNodes: %d\n", nNodes); if ( pGain_rw ) *pGain_rw = Vec_IntAlloc(1); pProgress = Extra_ProgressBarStart( stdout, nNodes ); @@ -489,7 +489,7 @@ int Abc_NtkRefactor3( Abc_Ntk_t * pNtk, Vec_Int_t **pGain_ref, int nNodeSizeMax, Abc_NtkStartReverseLevels( pNtk, 0 ); pManRef->nNodesBeg = Abc_NtkNodeNum(pNtk); nNodes = Abc_NtkObjNumMax(pNtk); - printf("nNodes: %d\n", nNodes); + //printf("nNodes: %d\n", nNodes); if (pGain_ref) *pGain_ref = Vec_IntAlloc(1); pProgress = Extra_ProgressBarStart( stdout, nNodes ); @@ -605,7 +605,7 @@ int Abc_NtkResubstitute3( Abc_Ntk_t * pNtk, Vec_Int_t **pGain_res, int nCutMax, // resynthesize each node once pManRes->nNodesBeg = Abc_NtkNodeNum(pNtk); nNodes = Abc_NtkObjNumMax(pNtk); - printf("nNodes: %d\n", nNodes); + //printf("nNodes: %d\n", nNodes); if (pGain_res) *pGain_res = Vec_IntAlloc(1); pProgress = Extra_ProgressBarStart( stdout, nNodes ); @@ -2732,7 +2732,7 @@ Rwr_ManAddTimeCuts( pManRwr, Abc_Clock() - clk ); pManRef->nNodesBeg = Abc_NtkNodeNum(pNtk); nNodes = Abc_NtkObjNumMax(pNtk); - printf("nNodes: %d\n", nNodes); + //printf("nNodes: %d\n", nNodes); if (pGain_res) *pGain_res = Vec_IntAlloc(1); if (pGain_ref) *pGain_ref = Vec_IntAlloc(1); if (pGain_rwr) *pGain_rwr = Vec_IntAlloc(1); @@ -5318,6 +5318,319 @@ s_ResubTime = Abc_Clock() - clkStart; return 1; } +// orchestration with sudo random decision list +int Abc_NtkOrchRand( Abc_Ntk_t * pNtk, Vec_Int_t **pGain_rwr, Vec_Int_t **pGain_res,Vec_Int_t **pGain_ref, Vec_Int_t **DecisionMask, char * DecisionFile, int Rand_Seed, int fUseZeros_rwr, int fUseZeros_ref, int fPlaceEnable, int nCutMax, int nStepsMax, int nLevelsOdc, int fUpdateLevel, int fVerbose, int fVeryVerbose, int nNodeSizeMax, int nConeSizeMax, int fUseDcs ) +{ + extern int Dec_GraphUpdateNetwork( Abc_Obj_t * pRoot, Dec_Graph_t * pGraph, int fUpdateLevel, int nGain ); + ProgressBar * pProgress; + // For resub + Abc_ManRes_t * pManRes; + Abc_ManCut_t * pManCutRes; + Odc_Man_t * pManOdc = NULL; + Dec_Graph_t * pFFormRes; + Vec_Ptr_t * vLeaves; + // For rewrite + Cut_Man_t * pManCutRwr; + Rwr_Man_t * pManRwr; + Dec_Graph_t * pGraph; + // For refactor + Abc_ManRef_t * pManRef; + Abc_ManCut_t * pManCutRef; + Dec_Graph_t * pFFormRef; + Vec_Ptr_t * vFanins; + + Abc_Obj_t * pNode; + FILE *fpt; + abctime clk, clkStart = Abc_Clock(); + int i, nNodes, nNodes_after, nGain, fCompl; + int RetValue = 1; + int ops_rwr = 0; + int ops_res = 0; + int ops_ref = 0; + int ops_null = 0; + int Valid_Len = 0; + //Vec_Int_t *Valid_Ops; + + //clock_t begin= clock(); + assert( Abc_NtkIsStrash(pNtk) ); + + // cleanup the AIG + Abc_AigCleanup((Abc_Aig_t *)pNtk->pManFunc); + + // start the managers resub + pManCutRes = Abc_NtkManCutStart( nCutMax, 100000, 100000, 100000 ); + pManRes = Abc_ManResubStart( nCutMax, ABC_RS_DIV1_MAX ); + if ( nLevelsOdc > 0 ) + pManOdc = Abc_NtkDontCareAlloc( nCutMax, nLevelsOdc, fVerbose, fVeryVerbose ); + // start the managers refactor + pManCutRef = Abc_NtkManCutStart( nNodeSizeMax, nConeSizeMax, 2, 1000 ); + pManRef = Abc_NtkManRefStart_1( nNodeSizeMax, nConeSizeMax, fUseDcs, fVerbose ); + pManRef->vLeaves = Abc_NtkManCutReadCutLarge( pManCutRef ); + // start the managers rewrite + pManRwr = Rwr_ManStart( 0 ); + if ( pManRwr == NULL ) + return 0; + + // compute the reverse levels if level update is requested + if ( fUpdateLevel ) + Abc_NtkStartReverseLevels( pNtk, 0 ); + + // 'Resub only' + + if ( Abc_NtkLatchNum(pNtk) ) { + Abc_NtkForEachLatch(pNtk, pNode, i) + pNode->pNext = (Abc_Obj_t *)pNode->pData; + } + + // cut manager for rewrite +clk = Abc_Clock(); + pManCutRwr = Abc_NtkStartCutManForRewrite( pNtk ); +Rwr_ManAddTimeCuts( pManRwr, Abc_Clock() - clk ); + pNtk->pManCut = pManCutRwr; + + if ( fVeryVerbose ) + Rwr_ScoresClean( pManRwr ); + + // resynthesize each node once + // resub + pManRes->nNodesBeg = Abc_NtkNodeNum(pNtk); + // rewrite + pManRwr->nNodesBeg = Abc_NtkNodeNum(pNtk); + // refactor + pManRef->nNodesBeg = Abc_NtkNodeNum(pNtk); + +//clock_t resyn_end=clock(); +//double resyn_time_spent = (double)(resyn_end-begin)/CLOCKS_PER_SEC; +//printf("time %f\n", resyn_time_spent); + nNodes = Abc_NtkObjNumMax(pNtk); + //printf("nNodes: %d\n", nNodes); + //for(int i=0; i < nNodes; i++){printf("mask check: %d\n", (*DecisionMask)->pArray[i]);} + //printf("mask size:%d", (**DecisionMask).nSize); + if (pGain_res) *pGain_res = Vec_IntAlloc(1); + if (pGain_ref) *pGain_ref = Vec_IntAlloc(1); + if (pGain_rwr) *pGain_rwr = Vec_IntAlloc(1); + Vec_Int_t *Valid_Ops = Vec_IntAlloc(1); + + pProgress = Extra_ProgressBarStart( stdout, nNodes ); + fpt = fopen(DecisionFile, "w"); + + Abc_NtkForEachNode( pNtk, pNode, i ) + { + //printf("Ochestration id: %d\n", pNode->Id); + int iterNode = pNode->Id; + Extra_ProgressBarUpdate( pProgress, i, NULL ); + // skip the constant node +// if ( Abc_NodeIsConst(pNode) ) +// continue; + // stop if all nodes have been tried once + if ( i >= nNodes ) + break; + // skip persistant nodes + if ( Abc_NodeIsPersistant(pNode) ) + { + //fprintf(fpt, "%d, %s, %d\n", pNode->Id, "None" , -99); + Vec_IntPush((*pGain_res), -99); + Vec_IntPush((*pGain_ref), -99); + Vec_IntPush((*pGain_rwr), -99); + continue; + } + // skip the nodes with many fanouts + if ( Abc_ObjFanoutNum(pNode) > 1000 ) + { + //fprintf(fpt, "%d, %s, %d\n", pNode->Id,"None", -99); + Vec_IntPush((*pGain_res), -99); + Vec_IntPush((*pGain_ref), -99); + Vec_IntPush((*pGain_rwr), -99); + continue; + } +clk = Abc_Clock(); + +// Generate random operation +// check transformability of all three operations + Vec_IntPush( (Valid_Ops), -1); + nGain = Rwr_NodeRewrite( pManRwr, pManCutRwr, pNode, fUpdateLevel, fUseZeros_rwr, fPlaceEnable ); + Vec_IntPush( (*pGain_rwr), nGain); + if (nGain > 0 || (nGain == 0 && fUseZeros_rwr)) + { + Vec_IntPush( (Valid_Ops), 0); + } + vLeaves = Abc_NodeFindCut( pManCutRes, pNode, 0 ); + pManRes->timeCut += Abc_Clock() - clk; + if ( pManOdc ) + { +clk = Abc_Clock(); + Abc_NtkDontCareClear( pManOdc ); + Abc_NtkDontCareCompute( pManOdc, pNode, vLeaves, pManRes->pCareSet ); +pManRes->timeTruth += Abc_Clock() - clk; + } +clk = Abc_Clock(); + pFFormRes = Abc_ManResubEval( pManRes, pNode, vLeaves, nStepsMax, fUpdateLevel, fVerbose ); +pManRes->timeRes += Abc_Clock() - clk; + Vec_IntPush((*pGain_res), pManRes->nLastGain); + if (pManRes->nLastGain > 0) + { + if ( pFFormRes != NULL ){ + Vec_IntPush( (Valid_Ops), 1); + } + } + + vFanins = Abc_NodeFindCut( pManCutRef, pNode, fUseDcs ); +pManRef->timeCut += Abc_Clock() - clk; +clk = Abc_Clock(); + pFFormRef = Abc_NodeRefactor_1( pManRef, pNode, vFanins, fUpdateLevel, fUseZeros_ref, fUseDcs, fVerbose ); +pManRef->timeRes += Abc_Clock() - clk; + + Vec_IntPush((*pGain_ref), pManRef->nLastGain); + if (pManRef->nLastGain > 0 || (pManRef->nLastGain ==0 && fUseZeros_ref)) + { + if ( pFFormRef != NULL ){ + Vec_IntPush( (Valid_Ops), 2); + } + } + Valid_Len = (Valid_Ops)->nSize; + //printf("The length of valid operations: %d\n", Valid_Len); + +//Pick a random operations from valid ones +if (Rand_Seed == -1) +{ + srand(time(NULL)); +} +else +{ + srand(Rand_Seed); +} + +int r = rand() % Valid_Len; + + if ((Valid_Ops)->pArray[r] == -1){ + (*DecisionMask)->pArray[iterNode] = -1; + ops_null++; + Vec_IntZero(Valid_Ops); // reset updates + continue; + } + else if ((Valid_Ops->pArray[r]) == 0){ + // apply rewrite + pGraph = (Dec_Graph_t *)Rwr_ManReadDecs(pManRwr); + fCompl = Rwr_ManReadCompl(pManRwr); + if ( fPlaceEnable ) + Abc_AigUpdateReset( (Abc_Aig_t *)pNtk->pManFunc ); + if ( fCompl ) Dec_GraphComplement( pGraph ); +clk = Abc_Clock(); + Dec_GraphUpdateNetwork( pNode, pGraph, fUpdateLevel, nGain ); +Rwr_ManAddTimeUpdate( pManRwr, Abc_Clock() - clk ); + if ( fCompl ) Dec_GraphComplement( pGraph ); + (*DecisionMask)->pArray[iterNode] = 0; + ops_rwr++; + Vec_IntZero(Valid_Ops); // reset updates + continue; + } + else if ((Valid_Ops->pArray[r] == 1)){ + // apply res + pManRes->nTotalGain += pManRes->nLastGain; +clk = Abc_Clock(); + Dec_GraphUpdateNetwork( pNode, pFFormRes, fUpdateLevel, pManRes->nLastGain ); +pManRes->timeNtk += Abc_Clock() - clk; + Dec_GraphFree( pFFormRes ); + (*DecisionMask)->pArray[iterNode] = 1; + ops_res++; + Vec_IntZero(Valid_Ops); // reset updates + continue; + } + else if ((Valid_Ops->pArray[r] == 2)){ +clk = Abc_Clock(); + if ( !Dec_GraphUpdateNetwork( pNode, pFFormRef, fUpdateLevel, pManRef->nLastGain ) ) + { + Dec_GraphFree( pFFormRef ); + RetValue = -1; + break; + } +pManRef->timeNtk += Abc_Clock() - clk; + Dec_GraphFree( pFFormRef ); + (*DecisionMask)->pArray[iterNode] = 2; + ops_ref++; + Vec_IntZero(Valid_Ops); // reset updates + continue; + } + } + //fwrite((**DecisionMask).pArray, sizeof(int), sizeof((**DecisionMask).pArray), fpt); + for (int i = 0; i < (nNodes); i++){ + fprintf(fpt, "%d\n", (*DecisionMask)->pArray[i]);} + fclose(fpt); +/* + printf("size of vector %d\n", Valid_Len); + printf("Nodes with rewrite: %d\n", ops_rwr); + printf("Nodes with resub: %d\n", ops_res); + printf("Nodes with refactor: %d\n", ops_ref); + printf("Nodes without updates: %d\n", ops_null); +*/ + Extra_ProgressBarStop( pProgress ); +// Rewrite +Rwr_ManAddTimeTotal( pManRwr, Abc_Clock() - clkStart ); + pManRwr->nNodesEnd = Abc_NtkNodeNum(pNtk); + +// Resub +pManRes->timeTotal = Abc_Clock() - clkStart; + pManRes->nNodesEnd = Abc_NtkNodeNum(pNtk); + +// Refactor +pManRef->timeTotal = Abc_Clock() - clkStart; + pManRef->nNodesEnd = Abc_NtkNodeNum(pNtk); + + // print statistics + if ( fVerbose ){ + Abc_ManResubPrint( pManRes ); + Rwr_ManPrintStats( pManRwr ); + Abc_NtkManRefPrintStats_1( pManRef ); + } + if ( fVeryVerbose ) + Rwr_ScoresReport( pManRwr ); + // delete the managers + // resub + Abc_ManResubStop( pManRes ); + Abc_NtkManCutStop( pManCutRes ); + // rewrite + Rwr_ManStop( pManRwr ); + Cut_ManStop( pManCutRwr ); + pNtk->pManCut = NULL; + // refactor + Abc_NtkManCutStop( pManCutRef ); + Abc_NtkManRefStop_1( pManRef ); + + if ( pManOdc ) Abc_NtkDontCareFree( pManOdc ); + + // clean the data field + Abc_NtkForEachObj( pNtk, pNode, i ) + pNode->pData = NULL; + + if ( Abc_NtkLatchNum(pNtk) ) { + Abc_NtkForEachLatch(pNtk, pNode, i) + pNode->pData = pNode->pNext, pNode->pNext = NULL; + } + + // put the nodes into the DFS order and reassign their IDs + Abc_NtkReassignIds( pNtk ); +// Abc_AigCheckFaninOrder( pNtk->pManFunc ); + + // fix the levels + if ( fUpdateLevel ) + Abc_NtkStopReverseLevels( pNtk ); + else + Abc_NtkLevel( pNtk ); + // check + if ( !Abc_NtkCheck( pNtk ) ) + { + printf( "Abc_NtkOchestraction: The network check has failed.\n" ); + return 0; + } + nNodes_after = Abc_NtkObjNumMax(pNtk); + //printf("nNodes after optimization: %d\n", nNodes_after); +//s_ResubTime = Abc_Clock() - clkStart; +//clock_t end=clock(); +//double time_spent = (double)(end-begin)/CLOCKS_PER_SEC; +//printf("time %f\n", time_spent); + return 1; +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// From 0fe977a33c422bd0957527efa3ee1cbec384222b Mon Sep 17 00:00:00 2001 From: CUNXI YU Date: Sun, 27 Aug 2023 11:18:35 -0600 Subject: [PATCH 02/67] correct the naming of augmentation --- src/base/abci/abc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 6e99d74810..6b5c4ebca6 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -164,7 +164,7 @@ static int Abc_CommandAllExact ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandTestExact ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandMajGen ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandOrchestrate ( Abc_Frame_t * pAbc, int argc, char ** argv ); -static int Abc_CommandAIGArgumentation ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAIGAugmentation ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandLogic ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandComb ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -918,7 +918,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Synthesis", "faultclasses", Abc_CommandFaultClasses, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "exact", Abc_CommandExact, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "orchestrate", Abc_CommandOrchestrate, 1 ); - Cmd_CommandAdd( pAbc, "Synthesis", "aigarg", Abc_CommandAIGArgumentation, 1 ); + Cmd_CommandAdd( pAbc, "Synthesis", "aigaug", Abc_CommandAIGAugmentation, 1 ); Cmd_CommandAdd( pAbc, "Exact synthesis", "bms_start", Abc_CommandBmsStart, 0 ); Cmd_CommandAdd( pAbc, "Exact synthesis", "bms_stop", Abc_CommandBmsStop, 0 ); @@ -7540,14 +7540,14 @@ int Abc_CommandOrchestrate( Abc_Frame_t * pAbc, int argc, char ** argv ) Synopsis [] - Description [AIG RTL Argumentation] + Description [AIG RTL Augmentation] SideEffects [] SeeAlso [] ***********************************************************************/ -int Abc_CommandAIGArgumentation( Abc_Frame_t * pAbc, int argc, char ** argv ) +int Abc_CommandAIGAugmentation( Abc_Frame_t * pAbc, int argc, char ** argv ) { Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc), * pDup; int c, RetValue; @@ -7690,15 +7690,15 @@ int Abc_CommandAIGArgumentation( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: aigarg [-s ] [-d ][-zZdsh]\n" ); + Abc_Print( -2, "usage: aigaug [-s ] [-d ][-zZdsh]\n" ); Abc_Print( -2, "\t performs technology-independent AIG random synthesis (node level) for RTL argumentation\n" ); - Abc_Print( -2, "\t-z : toggle using zero-cost replacements for rwr for aigarg [default = %s]\n", fUseZeros_rwr? "yes": "no" ); - Abc_Print( -2, "\t-Z : toggle using zero-cost replacements for ref for aigarg [default = %s]\n", fUseZeros_ref? "yes": "no" ); + Abc_Print( -2, "\t-z : toggle using zero-cost replacements for rwr for aigaug [default = %s]\n", fUseZeros_rwr? "yes": "no" ); + Abc_Print( -2, "\t-Z : toggle using zero-cost replacements for ref for aigaug [default = %s]\n", fUseZeros_ref? "yes": "no" ); Abc_Print( -2, "\t-d : record random synthesis decision made during argumentation [required filename; e.g., test.csv]\n"); Abc_Print( -2, "\t-s : set the random seed for random argumentation\n"); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); - Abc_Print( -2, "\tExample : read i10.aig;st;aigarg -s 1 -d test.csv;write i10_arg_1.aig;cec i10.aig i10_arg_1.aig\n"); + Abc_Print( -2, "\tExample : read i10.aig;st;aigaug -s 1 -d test.csv;write i10_arg_1.aig;cec i10.aig i10_arg_1.aig\n"); return 1; } From 855976c61d7eb50b238fb9f6e793d80bff1e8ed7 Mon Sep 17 00:00:00 2001 From: CUNXI YU Date: Sun, 27 Aug 2023 11:19:26 -0600 Subject: [PATCH 03/67] correct the naming of augmentation --- src/base/abci/abc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 6b5c4ebca6..94ca326df0 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -7691,11 +7691,11 @@ int Abc_CommandAIGAugmentation( Abc_Frame_t * pAbc, int argc, char ** argv ) usage: Abc_Print( -2, "usage: aigaug [-s ] [-d ][-zZdsh]\n" ); - Abc_Print( -2, "\t performs technology-independent AIG random synthesis (node level) for RTL argumentation\n" ); + Abc_Print( -2, "\t performs technology-independent AIG random synthesis (node level) for RTL augmentation\n" ); Abc_Print( -2, "\t-z : toggle using zero-cost replacements for rwr for aigaug [default = %s]\n", fUseZeros_rwr? "yes": "no" ); Abc_Print( -2, "\t-Z : toggle using zero-cost replacements for ref for aigaug [default = %s]\n", fUseZeros_ref? "yes": "no" ); - Abc_Print( -2, "\t-d : record random synthesis decision made during argumentation [required filename; e.g., test.csv]\n"); - Abc_Print( -2, "\t-s : set the random seed for random argumentation\n"); + Abc_Print( -2, "\t-d : record random synthesis decision made during augmentation [required filename; e.g., test.csv]\n"); + Abc_Print( -2, "\t-s : set the random seed for random augmentation\n"); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); Abc_Print( -2, "\tExample : read i10.aig;st;aigaug -s 1 -d test.csv;write i10_arg_1.aig;cec i10.aig i10_arg_1.aig\n"); From 7d80ea5cf9951fc2b37151a59abc8a71a2c6ed7e Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Wed, 13 Sep 2023 18:24:01 +0000 Subject: [PATCH 04/67] Adds unit testing framework to ABC Signed-off-by: Ethan Mahintorabi --- .github/workflows/build-posix-cmake.yml | 4 ++ CMakeLists.txt | 14 +++++++ test/CMakeLists.txt | 1 + test/gia/CMakeLists.txt | 11 +++++ test/gia/gia_test.cc | 55 +++++++++++++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 test/CMakeLists.txt create mode 100644 test/gia/CMakeLists.txt create mode 100644 test/gia/gia_test.cc diff --git a/.github/workflows/build-posix-cmake.yml b/.github/workflows/build-posix-cmake.yml index def198107e..6bbf1976ed 100644 --- a/.github/workflows/build-posix-cmake.yml +++ b/.github/workflows/build-posix-cmake.yml @@ -40,6 +40,10 @@ jobs: run: | cmake --build build + - name: Run Unit Tests + run: | + ctest --output-on-failure + - name: Test Executable run: | ./build/abc -c "r i10.aig; b; ps; b; rw -l; rw -lz; b; rw -lz; b; ps; cec" diff --git a/CMakeLists.txt b/CMakeLists.txt index cee9bc72fd..c04c112cfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,3 +108,17 @@ add_library(libabc-pic EXCLUDE_FROM_ALL ${ABC_SRC}) abc_properties(libabc-pic PUBLIC) set_property(TARGET libabc-pic PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET libabc-pic PROPERTY OUTPUT_NAME abc-pic) + +if(NOT DEFINED ABC_SKIP_TESTS) + enable_testing() + include(FetchContent) + FetchContent_Declare( + googletest + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + # Specify the commit you depend on and update it regularly. + URL "https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip" + ) + FetchContent_MakeAvailable(googletest) + include(GoogleTest) + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000..5a187fcac7 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(gia) \ No newline at end of file diff --git a/test/gia/CMakeLists.txt b/test/gia/CMakeLists.txt new file mode 100644 index 0000000000..012aca6db6 --- /dev/null +++ b/test/gia/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(gia_test gia_test.cc) + +target_link_libraries(gia_test + gtest + gtest_main + libabc +) + +gtest_discover_tests(gia_test + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/test/gia/gia_test.cc b/test/gia/gia_test.cc new file mode 100644 index 0000000000..c61f72f3ee --- /dev/null +++ b/test/gia/gia_test.cc @@ -0,0 +1,55 @@ +#include "gtest/gtest.h" + +#include "aig/gia/gia.h" + +namespace abc { + + +TEST(GiaTest, CanAllocateGiaManager) { + Gia_Man_t* aig_manager = Gia_ManStart(100); + + EXPECT_TRUE(aig_manager != nullptr); + Gia_ManStop(aig_manager); +} + +TEST(GiaTest, CanAddACi) { + Gia_Man_t* aig_manager = Gia_ManStart(100); + Gia_ManAppendCi(aig_manager); + + EXPECT_EQ(Gia_ManCiNum(aig_manager), 1); + Gia_ManStop(aig_manager); +} + +TEST(GiaTest, CanAddACo) { + Gia_Man_t* aig_manager = Gia_ManStart(100); + int input1 = Gia_ManAppendCi(aig_manager); + Gia_ManAppendCo(aig_manager, input1); + + EXPECT_EQ(Gia_ManCiNum(aig_manager), 1); + EXPECT_EQ(Gia_ManCoNum(aig_manager), 1); + Gia_ManStop(aig_manager); +} + +TEST(GiaTest, CanAddAnAndGate) { + Gia_Man_t* aig_manager = Gia_ManStart(100); + + int input1 = Gia_ManAppendCi(aig_manager); + int input2 = Gia_ManAppendCi(aig_manager); + + int and_output = Gia_ManAppendAnd(aig_manager, input1, input2); + Gia_ManAppendCo(aig_manager, and_output); + + Vec_Wrd_t* stimulus = Vec_WrdAlloc(2); + Vec_WrdPush(stimulus, /*A*/1); + Vec_WrdPush(stimulus, /*B*/1); + Vec_Wrd_t* output = Gia_ManSimPatSimOut(aig_manager, stimulus, /*fouts*/1); + + EXPECT_EQ(Gia_ManCiNum(aig_manager), 2); + EXPECT_EQ(Gia_ManCoNum(aig_manager), 1); + // A = 1, B = 1 -> A & B == 1 + EXPECT_EQ(Vec_WrdGetEntry(output, 0), 1); + Vec_WrdFree(output); + Gia_ManStop(aig_manager); +} + +} // namespace dpl \ No newline at end of file From 09013f3a6ea7276f289d790a217ca86b863eaeb9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 15 Sep 2023 22:44:31 +0800 Subject: [PATCH 05/67] New command &gen_hie to generate hierarchical designs. --- src/aig/gia/gia.h | 2 +- src/aig/gia/giaMan.c | 209 ++++++++++++++++++++++++++++++++++++++++++- src/base/abci/abc.c | 57 +++++++++++- 3 files changed, 260 insertions(+), 8 deletions(-) diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index d4edc1237a..68266bb2d9 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -1527,7 +1527,7 @@ extern void Gia_ManPrintStatsMiter( Gia_Man_t * p, int fVerbose ) extern void Gia_ManSetRegNum( Gia_Man_t * p, int nRegs ); extern void Gia_ManReportImprovement( Gia_Man_t * p, Gia_Man_t * pNew ); extern void Gia_ManPrintNpnClasses( Gia_Man_t * p ); -extern void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter ); +extern void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb ); /*=== giaMem.c ===========================================================*/ extern Gia_MmFixed_t * Gia_MmFixedStart( int nEntrySize, int nEntriesMax ); extern void Gia_MmFixedStop( Gia_MmFixed_t * p, int fVerbose ); diff --git a/src/aig/gia/giaMan.c b/src/aig/gia/giaMan.c index e8f9bca327..0efb5b29fa 100644 --- a/src/aig/gia/giaMan.c +++ b/src/aig/gia/giaMan.c @@ -1291,7 +1291,7 @@ void Gia_ManDumpModuleName( FILE * pFile, char * pName ) else fprintf( pFile, "_" ); } -void Gia_ManDumpInterface( Gia_Man_t * p, FILE * pFile ) +void Gia_ManDumpInterface2( Gia_Man_t * p, FILE * pFile ) { int fPrintClk = 0; fprintf( pFile, "module " ); @@ -1324,7 +1324,6 @@ void Gia_ManDumpInterface( Gia_Man_t * p, FILE * pFile ) fprintf( pFile, "endmodule\n\n" ); } - /**Function************************************************************* Synopsis [Compute arrival/required times.] @@ -1407,7 +1406,7 @@ void Gia_ManWriteNames( FILE * pFile, char c, int n, Vec_Ptr_t * vNames, int Sta fFirst = 0; } } -void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter ) +void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb ) { Gia_Obj_t * pObj; Vec_Bit_t * vInvs, * vUsed; @@ -1415,6 +1414,13 @@ void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int int nDigitsI = Abc_Base10Log( Gia_ManPiNum(p) ); int nDigitsO = Abc_Base10Log( Gia_ManPoNum(p) ); int i, k, iObj, nRegs = Gia_ManRegNum(p); + if ( fInterComb ) + { + extern void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ); + Gia_ManDumpInterface( p, pFileName ); + return; + } + FILE * pFile = fopen( pFileName, "wb" ); if ( pFile == NULL ) { @@ -1423,7 +1429,7 @@ void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int } if ( fInter || nRegs ) - Gia_ManDumpInterface( p, pFile ); + Gia_ManDumpInterface2( p, pFile ); //Gia_ManSetRegNum( p, 0 ); p->nRegs = 0; @@ -1588,6 +1594,201 @@ void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int Gia_ManSetRegNum( p, nRegs ); } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ) +{ + Gia_Obj_t * pObj; + Vec_Bit_t * vInvs, * vUsed; + int nDigits = Abc_Base10Log( Gia_ManObjNum(p) ); + int nDigitsI = Abc_Base10Log( Gia_ManPiNum(p) ); + int nDigitsO = Abc_Base10Log( Gia_ManPoNum(p) ); + int i; + + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + { + printf( "Cannot open output file \"%s\".\n", pFileName ); + return; + } + + vInvs = Gia_ManGenUsed( p, 0 ); + vUsed = Gia_ManGenUsed( p, 1 ); + + fprintf( pFile, "module " ); + Gia_ManDumpModuleName( pFile, p->pName ); + fprintf( pFile, "_wrapper" ); + fprintf( pFile, " ( _i_, _o_ );\n\n" ); + fprintf( pFile, " input [%d:0] _i_;\n", Gia_ManCiNum(p)-1 ); + fprintf( pFile, " output [%d:0] _o_;\n\n", Gia_ManCoNum(p)-1 ); + + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 8, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 9, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " assign { " ); + Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, NULL ); + fprintf( pFile, " } = _i_;\n\n" ); + + fprintf( pFile, " assign _o_ = { " ); + Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, NULL ); + fprintf( pFile, " };\n\n" ); + + if ( Vec_BitCount(vUsed) ) + { + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'n', Gia_ManObjNum(p), NULL, 7, 4, vUsed ); + fprintf( pFile, ";\n\n" ); + } + + if ( Vec_BitCount(vInvs) ) + { + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'i', Gia_ManObjNum(p), NULL, 7, 4, vInvs ); + fprintf( pFile, ";\n\n" ); + } + + // input inverters + Gia_ManForEachCi( p, pObj, i ) + { + if ( Vec_BitEntry(vUsed, Gia_ObjId(p, pObj)) ) + { + fprintf( pFile, " buf ( %s,", Gia_ObjGetDumpName(NULL, 'n', Gia_ObjId(p, pObj), nDigits) ); + fprintf( pFile, " %s );\n", Gia_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) ); + } + if ( Vec_BitEntry(vInvs, Gia_ObjId(p, pObj)) ) + { + fprintf( pFile, " not ( %s,", Gia_ObjGetDumpName(NULL, 'i', Gia_ObjId(p, pObj), nDigits) ); + fprintf( pFile, " %s );\n", Gia_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) ); + } + } + + // internal nodes and their inverters + fprintf( pFile, "\n" ); + Gia_ManForEachAnd( p, pObj, i ) + { + fprintf( pFile, " and ( %s,", Gia_ObjGetDumpName(NULL, 'n', i, nDigits) ); + fprintf( pFile, " %s,", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0(pObj, i), nDigits) ); + fprintf( pFile, " %s );\n", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC1(pObj)? 'i':'n'), Gia_ObjFaninId1(pObj, i), nDigits) ); + if ( Vec_BitEntry(vInvs, i) ) + { + fprintf( pFile, " not ( %s,", Gia_ObjGetDumpName(NULL, 'i', i, nDigits) ); + fprintf( pFile, " %s );\n", Gia_ObjGetDumpName(NULL, 'n', i, nDigits) ); + } + } + + // output drivers + fprintf( pFile, "\n" ); + Gia_ManForEachCo( p, pObj, i ) + { + fprintf( pFile, " buf ( %s, ", Gia_ObjGetDumpName(p->vNamesOut, 'z', i, nDigitsO) ); + if ( Gia_ObjIsConst0(Gia_ObjFanin0(pObj)) ) + fprintf( pFile, "1\'b%d );\n", Gia_ObjFaninC0(pObj) ); + else + fprintf( pFile, "%s );\n", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0p(p, pObj), nDigits) ); + } + + fprintf( pFile, "\nendmodule\n\n" ); + fclose( pFile ); + + Vec_BitFree( vInvs ); + Vec_BitFree( vUsed ); +} + + +/**Function************************************************************* + + Synopsis [Generate hierarchical design.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Gia_FreeMany( Gia_Man_t ** pGias, int nGias ) +{ + int i; + for ( i = 0; i < nGias; i++ ) + Gia_ManStopP( &pGias[i] ); +} +void Gia_GenSandwich( char ** pFNames, int nFNames ) +{ + FILE * pFile = NULL; + char * pFileName = (char *)"sandwich.v"; + Gia_Man_t * pGias[16] = {0}; + int i, k; + assert( nFNames <= 16 ); + for ( i = 0; i < nFNames; i++ ) + { + FILE * pFile = fopen( pFNames[i], "rb" ); + if ( pFile == NULL ) { + printf( "Cannot open input file \"%s\".\n", pFNames[i] ); + Gia_FreeMany( pGias, nFNames ); + return; + } + fclose( pFile ); + pGias[i] = Gia_AigerRead( pFNames[i], 0, 0, 0 ); + if ( pGias[i] == NULL ) { + printf( "Failed to read an AIG from file \"%s\".\n", pFNames[i] ); + Gia_FreeMany( pGias, nFNames ); + return; + } + } + for ( i = 0; i < nFNames-1; i++ ) + if ( Gia_ManPoNum(pGias[i]) < Gia_ManPiNum(pGias[i+1]) ) { + printf( "AIG in file \"%s\" has fewer outputs than inputs of AIG in file \"%s\".\n", pFNames[i], pFNames[i+1] ); + Gia_FreeMany( pGias, nFNames ); + return; + } + pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + { + printf( "Cannot open output file \"%s\".\n", pFileName ); + Gia_FreeMany( pGias, nFNames ); + return; + } + fprintf( pFile, "\n" ); + for ( i = 0; i < nFNames; i++ ) + fprintf( pFile, "`include \"%s\"\n", Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v") ); + fprintf( pFile, "\n" ); + fprintf( pFile, "module sandwich ( in, out );\n" ); + fprintf( pFile, " input [%3d:0] in;\n", Gia_ManPiNum(pGias[0])-1 ); + fprintf( pFile, " output [%3d:0] out;\n", Gia_ManPoNum(pGias[nFNames-1])-1 ); + fprintf( pFile, " wire [%3d:0] tmp0 = in;\n", Gia_ManPiNum(pGias[0])-1 ); + for ( i = 0; i < nFNames; i++ ) { + fprintf( pFile, " wire [%3d:0] tmp%d; ", Gia_ManPoNum(pGias[i])-1, i+1 ); + Gia_ManDumpModuleName( pFile, pGias[i]->pName ); + fprintf( pFile, "_wrapper" ); + for ( k = strlen(pGias[i]->pName); k < 24; k++ ) + fprintf( pFile, " " ); + fprintf( pFile, " i%d ( tmp%d, tmp%d );\n", i+1, i, i+1 ); + } + fprintf( pFile, " assign out = tmp%d;\n", nFNames ); + fprintf( pFile, "endmodule\n" ); + fclose( pFile ); + for ( i = 0; i < nFNames; i++ ) { + Gia_ManDumpVerilog( pGias[i], Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v"), NULL, 0, 0, 1 ); + printf( "Dumped Verilog file \"%s\"\n", Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v") ); + } + Gia_FreeMany( pGias, nFNames ); + printf( "Dumped hierarchical design into file \"%s\"\n", pFileName ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index e866678829..c8fa8e141a 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -595,6 +595,7 @@ static int Abc_CommandAbc9Cfs ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9ProdAdd ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9AddFlop ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9BMiter ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9GenHie ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Test ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1364,6 +1365,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&prodadd", Abc_CommandAbc9ProdAdd, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&addflop", Abc_CommandAbc9AddFlop, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&bmiter", Abc_CommandAbc9BMiter, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&gen_hie", Abc_CommandAbc9GenHie, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&test", Abc_CommandAbc9Test, 0 ); { @@ -31762,13 +31764,14 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) int fUnique = 0; int fVerilog = 0; int fInter = 0; + int fInterComb = 0; int fVerBufs = 0; int fMiniAig = 0; int fMiniLut = 0; int fWriteNewLine = 0; int fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "upibmlnvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "upicbmlnvh" ) ) != EOF ) { switch ( c ) { @@ -31781,6 +31784,9 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'i': fInter ^= 1; break; + case 'c': + fInterComb ^= 1; + break; case 'b': fVerBufs ^= 1; break; @@ -31822,7 +31828,7 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) Gia_ManStop( pGia ); } else if ( fVerilog ) - Gia_ManDumpVerilog( pAbc->pGia, pFileName, NULL, fVerBufs, fInter ); + Gia_ManDumpVerilog( pAbc->pGia, pFileName, NULL, fVerBufs, fInter, fInterComb ); else if ( fMiniAig ) Gia_ManWriteMiniAig( pAbc->pGia, pFileName ); else if ( fMiniLut ) @@ -31832,11 +31838,12 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &w [-upibmlnvh] \n" ); + Abc_Print( -2, "usage: &w [-upicbmlnvh] \n" ); Abc_Print( -2, "\t writes the current AIG into the AIGER file\n" ); Abc_Print( -2, "\t-u : toggle writing canonical AIG structure [default = %s]\n", fUnique? "yes" : "no" ); Abc_Print( -2, "\t-p : toggle writing Verilog with 'and' and 'not' [default = %s]\n", fVerilog? "yes" : "no" ); Abc_Print( -2, "\t-i : toggle writing the interface module in Verilog [default = %s]\n", fInter? "yes" : "no" ); + Abc_Print( -2, "\t-c : toggle writing the interface module in Verilog [default = %s]\n", fInterComb? "yes" : "no" ); Abc_Print( -2, "\t-b : toggle writing additional buffers in Verilog [default = %s]\n", fVerBufs? "yes" : "no" ); Abc_Print( -2, "\t-m : toggle writing MiniAIG rather than AIGER [default = %s]\n", fMiniAig? "yes" : "no" ); Abc_Print( -2, "\t-l : toggle writing MiniLUT rather than AIGER [default = %s]\n", fMiniLut? "yes" : "no" ); @@ -51569,6 +51576,50 @@ int Abc_CommandAbc9BMiter( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9GenHie( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Gia_GenSandwich( char ** pFNames, int nFNames ); + 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; + } + } + char ** pArgvNew = argv + globalUtilOptind; + int nArgcNew = argc - globalUtilOptind; + Gia_GenSandwich( pArgvNew, nArgcNew ); + return 0; +usage: + Abc_Print( -2, "usage: &gen_hie [-vh] ... \n" ); + Abc_Print( -2, "\t generates a hierarchical design\n" ); + Abc_Print( -2, "\t-v : toggles printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t : the AIG files for the instance modules\n"); + Abc_Print( -2, "\t (the PO count of should not be less than the PI count of )\n"); + return 1;} + + /**Function************************************************************* Synopsis [] From 57cc2bd08985f7d95a49de50f3ba0ed7a1f5ceb9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 15 Sep 2023 22:51:11 +0800 Subject: [PATCH 06/67] Compiler problem. --- src/base/abci/abc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index c8fa8e141a..79012c8508 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -51592,6 +51592,8 @@ int Abc_CommandAbc9GenHie( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Gia_GenSandwich( char ** pFNames, int nFNames ); int c, fVerbose = 0; + char ** pArgvNew; + int nArgcNew; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF ) { @@ -51606,8 +51608,8 @@ int Abc_CommandAbc9GenHie( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } } - char ** pArgvNew = argv + globalUtilOptind; - int nArgcNew = argc - globalUtilOptind; + pArgvNew = argv + globalUtilOptind; + nArgcNew = argc - globalUtilOptind; Gia_GenSandwich( pArgvNew, nArgcNew ); return 0; usage: From 318d5cb54bd3c1de807139a34667f4d963ea352c Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 15 Sep 2023 23:10:42 +0800 Subject: [PATCH 07/67] Do not create spec outputs in the boundary miter. --- src/aig/gia/giaDup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aig/gia/giaDup.c b/src/aig/gia/giaDup.c index 6dee2c26fe..db4072d71b 100644 --- a/src/aig/gia/giaDup.c +++ b/src/aig/gia/giaDup.c @@ -5708,8 +5708,8 @@ Gia_Man_t * Gia_ManBoundaryMiter( Gia_Man_t * p1, Gia_Man_t * p2, int fVerbose ) } Gia_ManForEachCo( p2, pObj, i ) Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) ); - Gia_ManForEachCo( p1, pObj, i ) - Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) ); + //Gia_ManForEachCo( p1, pObj, i ) + // Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) ); Vec_IntForEachEntry( vLits, iLit, i ) Gia_ManAppendCo( pNew, iLit ); Vec_IntFree( vLits ); From 475c8dad8ecbbe3cc1c864fb3462c83438184f6d Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 16 Sep 2023 07:13:10 +0800 Subject: [PATCH 08/67] Compiler problem. --- src/base/abci/abc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 5a755ea1f0..a1ee17305a 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -7576,7 +7576,11 @@ int Abc_CommandAIGAugmentation( Abc_Frame_t * pAbc, int argc, char ** argv ) int Rand_Seed; //int sOpsOrder; size_t NtkSize; - char *DecisionFile; + char *DecisionFile = NULL; + Vec_Int_t *DecisionMask; + Vec_Int_t *pGain_rwr; + Vec_Int_t *pGain_res; + Vec_Int_t *pGain_ref; //FILE *maskFile; extern void Rwr_Precompute(); extern int Abc_NtkOrchRand( Abc_Ntk_t * pNtk, Vec_Int_t **pGain_rwr, Vec_Int_t **pGain_res,Vec_Int_t **pGain_ref, Vec_Int_t **DecisionMask, char *DecisionFile, int Rand_Seed, int fUseZeros_rwr, int fUseZeros_ref, int fPlaceEnable, int nCutsMax, int nNodesMax, int nLevelsOdc, int fUpdateLevel, int fVerbose, int fVeryVerbose, int nNodeSizeMax, int nConeSizeMax, int fUseDcs ); @@ -7665,15 +7669,9 @@ int Abc_CommandAIGAugmentation( Abc_Frame_t * pAbc, int argc, char ** argv ) } NtkSize = Abc_NtkObjNumMax(pNtk); - - - Vec_Int_t *DecisionMask = Vec_IntAlloc(1); + DecisionMask = Vec_IntAlloc(1); for (int i=0; i Date: Sun, 17 Sep 2023 11:29:26 +0800 Subject: [PATCH 09/67] Revert "Merge pull request #247 from QuantamHD/abc_unit_tests" This reverts commit d91a2a049adec1797c7fa4aaeaef02a3c168734a, reversing changes made to 475c8dad8ecbbe3cc1c864fb3462c83438184f6d. --- .github/workflows/build-posix-cmake.yml | 4 -- CMakeLists.txt | 14 ------- test/CMakeLists.txt | 1 - test/gia/CMakeLists.txt | 11 ----- test/gia/gia_test.cc | 55 ------------------------- 5 files changed, 85 deletions(-) delete mode 100644 test/CMakeLists.txt delete mode 100644 test/gia/CMakeLists.txt delete mode 100644 test/gia/gia_test.cc diff --git a/.github/workflows/build-posix-cmake.yml b/.github/workflows/build-posix-cmake.yml index 6bbf1976ed..def198107e 100644 --- a/.github/workflows/build-posix-cmake.yml +++ b/.github/workflows/build-posix-cmake.yml @@ -40,10 +40,6 @@ jobs: run: | cmake --build build - - name: Run Unit Tests - run: | - ctest --output-on-failure - - name: Test Executable run: | ./build/abc -c "r i10.aig; b; ps; b; rw -l; rw -lz; b; rw -lz; b; ps; cec" diff --git a/CMakeLists.txt b/CMakeLists.txt index c04c112cfa..cee9bc72fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,17 +108,3 @@ add_library(libabc-pic EXCLUDE_FROM_ALL ${ABC_SRC}) abc_properties(libabc-pic PUBLIC) set_property(TARGET libabc-pic PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET libabc-pic PROPERTY OUTPUT_NAME abc-pic) - -if(NOT DEFINED ABC_SKIP_TESTS) - enable_testing() - include(FetchContent) - FetchContent_Declare( - googletest - DOWNLOAD_EXTRACT_TIMESTAMP TRUE - # Specify the commit you depend on and update it regularly. - URL "https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip" - ) - FetchContent_MakeAvailable(googletest) - include(GoogleTest) - add_subdirectory(test) -endif() \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 5a187fcac7..0000000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(gia) \ No newline at end of file diff --git a/test/gia/CMakeLists.txt b/test/gia/CMakeLists.txt deleted file mode 100644 index 012aca6db6..0000000000 --- a/test/gia/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_executable(gia_test gia_test.cc) - -target_link_libraries(gia_test - gtest - gtest_main - libabc -) - -gtest_discover_tests(gia_test - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) \ No newline at end of file diff --git a/test/gia/gia_test.cc b/test/gia/gia_test.cc deleted file mode 100644 index c61f72f3ee..0000000000 --- a/test/gia/gia_test.cc +++ /dev/null @@ -1,55 +0,0 @@ -#include "gtest/gtest.h" - -#include "aig/gia/gia.h" - -namespace abc { - - -TEST(GiaTest, CanAllocateGiaManager) { - Gia_Man_t* aig_manager = Gia_ManStart(100); - - EXPECT_TRUE(aig_manager != nullptr); - Gia_ManStop(aig_manager); -} - -TEST(GiaTest, CanAddACi) { - Gia_Man_t* aig_manager = Gia_ManStart(100); - Gia_ManAppendCi(aig_manager); - - EXPECT_EQ(Gia_ManCiNum(aig_manager), 1); - Gia_ManStop(aig_manager); -} - -TEST(GiaTest, CanAddACo) { - Gia_Man_t* aig_manager = Gia_ManStart(100); - int input1 = Gia_ManAppendCi(aig_manager); - Gia_ManAppendCo(aig_manager, input1); - - EXPECT_EQ(Gia_ManCiNum(aig_manager), 1); - EXPECT_EQ(Gia_ManCoNum(aig_manager), 1); - Gia_ManStop(aig_manager); -} - -TEST(GiaTest, CanAddAnAndGate) { - Gia_Man_t* aig_manager = Gia_ManStart(100); - - int input1 = Gia_ManAppendCi(aig_manager); - int input2 = Gia_ManAppendCi(aig_manager); - - int and_output = Gia_ManAppendAnd(aig_manager, input1, input2); - Gia_ManAppendCo(aig_manager, and_output); - - Vec_Wrd_t* stimulus = Vec_WrdAlloc(2); - Vec_WrdPush(stimulus, /*A*/1); - Vec_WrdPush(stimulus, /*B*/1); - Vec_Wrd_t* output = Gia_ManSimPatSimOut(aig_manager, stimulus, /*fouts*/1); - - EXPECT_EQ(Gia_ManCiNum(aig_manager), 2); - EXPECT_EQ(Gia_ManCoNum(aig_manager), 1); - // A = 1, B = 1 -> A & B == 1 - EXPECT_EQ(Vec_WrdGetEntry(output, 0), 1); - Vec_WrdFree(output); - Gia_ManStop(aig_manager); -} - -} // namespace dpl \ No newline at end of file From 2f5b81119b1bef37fc7637384157cf7238ab92f9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 17 Sep 2023 12:17:27 +0800 Subject: [PATCH 10/67] Experiments with retiming. --- src/aig/gia/gia.h | 3 ++ src/aig/gia/giaMan.c | 2 + src/aig/gia/giaMini.c | 92 +++++++++++++++++++++++++++++++++++++++++ src/aig/gia/giaSif.c | 9 +++- src/base/main/abcapis.h | 3 ++ 5 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index 68266bb2d9..dab6770bb5 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -241,6 +241,9 @@ struct Gia_Man_t_ Vec_Int_t vSuppVars; // used variables Vec_Int_t vVarMap; // used variables Gia_Dat_t * pUData; + // retiming data + Vec_Str_t * vStopsF; + Vec_Str_t * vStopsB; }; diff --git a/src/aig/gia/giaMan.c b/src/aig/gia/giaMan.c index 0efb5b29fa..a48da5c291 100644 --- a/src/aig/gia/giaMan.c +++ b/src/aig/gia/giaMan.c @@ -156,6 +156,8 @@ void Gia_ManStop( Gia_Man_t * p ) Vec_IntErase( &p->vHash ); Vec_IntErase( &p->vHTable ); Vec_IntErase( &p->vRefs ); + Vec_StrFreeP( &p->vStopsF ); + Vec_StrFreeP( &p->vStopsB ); ABC_FREE( p->pData2 ); ABC_FREE( p->pTravIds ); ABC_FREE( p->pPlacement ); diff --git a/src/aig/gia/giaMini.c b/src/aig/gia/giaMini.c index c0473fea3d..85647eac51 100644 --- a/src/aig/gia/giaMini.c +++ b/src/aig/gia/giaMini.c @@ -1228,6 +1228,98 @@ void Gia_MiniAigGenerateFromFile() Mini_AigStop( p ); } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Str_t * Gia_ManRetimableF( Gia_Man_t * p, int * pRst, int * pSet, int * pEna ) +{ + Vec_Str_t * vStops = Vec_StrStart( Gia_ManObjNum(p) ); + Vec_Int_t * vTemps = Vec_IntStartFull( 3*Gia_ManObjNum(p) ); + Gia_Obj_t * pObj, * pObjRi, * pObjRo; int i; + char * pStops = Vec_StrArray(vStops); + assert( Gia_ManRegNum(p) > 0 ); + Gia_ManForEachRiRo( p, pObjRi, pObjRo, i ) { + Vec_IntWriteEntry( vTemps, 3*Gia_ObjId(p, pObjRo) + 0, pRst[i] ); + Vec_IntWriteEntry( vTemps, 3*Gia_ObjId(p, pObjRo) + 1, pSet[i] ); + Vec_IntWriteEntry( vTemps, 3*Gia_ObjId(p, pObjRo) + 2, pEna[i] ); + } + Gia_ManForEachAnd( p, pObj, i ) { + int * pFan0 = Vec_IntEntryP( vTemps, 3*Gia_ObjFaninId0(pObj, i) ); + int * pFan1 = Vec_IntEntryP( vTemps, 3*Gia_ObjFaninId1(pObj, i) ); + int * pNode = Vec_IntEntryP( vTemps, 3*i ); + pStops[i] = (char)1; + if ( pFan0[0] != -1 && pFan0[0] == pFan1[0] && pFan0[1] == pFan1[1] && pFan0[2] == pFan1[2] ) + pStops[i] = (char)0, pNode[0] = pFan0[0], pNode[1] = pFan0[1], pNode[2] = pFan0[2]; + } + Vec_IntFree( vTemps ); + return vStops; +} +Vec_Str_t * Gia_ManRetimableB( Gia_Man_t * p, int * pRst, int * pSet, int * pEna ) +{ + Vec_Str_t * vStops = Vec_StrStart( Gia_ManObjNum(p) ); + Vec_Int_t * vTemps = Vec_IntStartFull( 3*Gia_ManObjNum(p) ); + Gia_Obj_t * pObj, * pObjRi, * pObjRo; int i, n; + char * pStops = Vec_StrArray(vStops); + assert( Gia_ManRegNum(p) > 0 ); + Gia_ManForEachRiRo( p, pObjRi, pObjRo, i ) { + Vec_IntWriteEntry( vTemps, 3*Gia_ObjFaninId0p(p, pObjRi) + 0, pRst[i] ); + Vec_IntWriteEntry( vTemps, 3*Gia_ObjFaninId0p(p, pObjRi) + 1, pSet[i] ); + Vec_IntWriteEntry( vTemps, 3*Gia_ObjFaninId0p(p, pObjRi) + 2, pEna[i] ); + } + Gia_ManForEachAndReverse( p, pObj, i ) { + int iFans[2] = { Gia_ObjFaninId0(pObj, i), Gia_ObjFaninId1(pObj, i) }; + int * pFans[2] = { Vec_IntEntryP( vTemps, 3*iFans[0] ), Vec_IntEntryP( vTemps, 3*iFans[1] ) }; + int * pNode = Vec_IntEntryP( vTemps, 3*i ); + if ( pNode[0] == -1 ) + continue; + for ( n = 0; n < 2; n++ ) + if ( pFans[n][0] == -1 ) + pStops[iFans[n]] = (char)1, pFans[n][0] = pNode[0], pFans[n][1] = pNode[1], pFans[n][2] = pNode[2]; + else if ( pFans[n][0] != pNode[0] || pFans[n][1] != pNode[1] || pFans[n][2] != pNode[2] ) + pStops[iFans[n]] = (char)0; + } + pStops[0] = (char)0; + Gia_ManForEachCi( p, pObj, i ) + pStops[Gia_ObjId(p, pObj)] = (char)0; + Gia_ManForEachAnd( p, pObj, i ) + pStops[i] = (char)!pStops[i]; + Vec_IntFree( vTemps ); + return vStops; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_FrameSetRetimingData( Abc_Frame_t * pAbc, int * pRst, int * pSet, int * pEna ) +{ + Gia_Man_t * pGia; + if ( pAbc == NULL ) + printf( "ABC framework is not initialized by calling Abc_Start()\n" ); + pGia = Abc_FrameReadGia( pAbc ); + if ( pGia == NULL ) + printf( "Current network in ABC framework is not defined.\n" ); + assert( pGia->vStopsF == NULL ); + assert( pGia->vStopsB == NULL ); + pGia->vStopsF = Gia_ManRetimableF( pGia, pRst, pSet, pEna ); + pGia->vStopsB = Gia_ManRetimableB( pGia, pRst, pSet, pEna ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/aig/gia/giaSif.c b/src/aig/gia/giaSif.c index db7629fb30..c52ab4dd93 100644 --- a/src/aig/gia/giaSif.c +++ b/src/aig/gia/giaSif.c @@ -490,13 +490,16 @@ int Gia_ManSifCheckIter( Gia_Man_t * p, Vec_Int_t * vCuts, Vec_Int_t * vTimes, i } int Gia_ManSifCheckPeriod( Gia_Man_t * p, Vec_Int_t * vCuts, Vec_Int_t * vTimes, int nLutSize, int Period, int * pIters ) { - Gia_Obj_t * pObj; int i, Id, nSize = nLutSize+1; + Gia_Obj_t * pObj; int i, Id, Stop, nSize = nLutSize+1; assert( Gia_ManRegNum(p) > 0 ); Gia_ManForEachCiId( p, Id, i ) Vec_IntWriteEntry( vCuts, Id*nSize, 1 ); Gia_ManForEachCiId( p, Id, i ) Vec_IntWriteEntry( vCuts, Id*nSize+1, Id << 8 ); Vec_IntFill( vTimes, Gia_ManObjNum(p), -Period ); + if ( p->vStopsF ) + Vec_StrForEachEntry( p->vStopsF, Stop, i ) + if ( Stop ) Vec_IntWriteEntry( vTimes, i, 0 ); Vec_IntWriteEntry( vTimes, 0, 0 ); Gia_ManForEachPi( p, pObj, i ) Vec_IntWriteEntry( vTimes, Gia_ObjId(p, pObj), 0 ); @@ -510,6 +513,10 @@ int Gia_ManSifCheckPeriod( Gia_Man_t * p, Vec_Int_t * vCuts, Vec_Int_t * vTimes, Gia_ManForEachObj( p, pObj, i ) if ( Vec_IntEntry(vTimes, Gia_ObjId(p, pObj)) > 2*Period ) return 0; + if ( p->vStopsB ) + Vec_StrForEachEntry( p->vStopsB, Stop, i ) + if ( Stop && Vec_IntEntry(vTimes, i) > Period ) + return 0; } return 0; } diff --git a/src/base/main/abcapis.h b/src/base/main/abcapis.h index d34306bafe..e1e05f4c7d 100644 --- a/src/base/main/abcapis.h +++ b/src/base/main/abcapis.h @@ -106,6 +106,9 @@ extern ABC_DLL int * Abc_FrameReadBoxes( Abc_Frame_t * pAbc ); extern ABC_DLL int Abc_FrameReadProbStatus( Abc_Frame_t * pAbc ); extern ABC_DLL void * Abc_FrameReadCex( Abc_Frame_t * pAbc ); +// procedure to set retiming data +extern ABC_DLL void Abc_FrameSetRetimingData( Abc_Frame_t * pAbc, int * pRst, int * pSet, int * pEna ); + // procedure to return sequential equivalences extern ABC_DLL int * Abc_FrameReadMiniAigEquivClasses( Abc_Frame_t * pAbc ); From da635a2995304b03d6ed58e434e333a89a68c70c Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 17 Sep 2023 12:18:12 +0800 Subject: [PATCH 11/67] Updating .gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c745dfb57f..cbb4241526 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ tags /cmake /cscope +abc.history From 9399faac485e842f3409892181d2bdab986a7137 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 17 Sep 2023 12:40:33 +0800 Subject: [PATCH 12/67] Improvements to &gen_hie. --- src/aig/gia/giaMan.c | 3 +-- src/base/abci/abc.c | 35 +++++++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/aig/gia/giaMan.c b/src/aig/gia/giaMan.c index a48da5c291..2449b5df75 100644 --- a/src/aig/gia/giaMan.c +++ b/src/aig/gia/giaMan.c @@ -1728,10 +1728,9 @@ void Gia_FreeMany( Gia_Man_t ** pGias, int nGias ) for ( i = 0; i < nGias; i++ ) Gia_ManStopP( &pGias[i] ); } -void Gia_GenSandwich( char ** pFNames, int nFNames ) +void Gia_GenSandwich( char ** pFNames, int nFNames, char * pFileName ) { FILE * pFile = NULL; - char * pFileName = (char *)"sandwich.v"; Gia_Man_t * pGias[16] = {0}; int i, k; assert( nFNames <= 16 ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index a1ee17305a..4bb3a43441 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -51755,15 +51755,24 @@ int Abc_CommandAbc9BMiter( Abc_Frame_t * pAbc, int argc, char ** argv ) ***********************************************************************/ int Abc_CommandAbc9GenHie( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern void Gia_GenSandwich( char ** pFNames, int nFNames ); + extern void Gia_GenSandwich( char ** pFNames, int nFNames, char * pFileName ); + char * pFileName = (char *)"sandwich.v"; int c, fVerbose = 0; char ** pArgvNew; int nArgcNew; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "Fvh" ) ) != EOF ) { switch ( c ) { + case 'F': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-F\" should be followed by a file name.\n" ); + goto usage; + } + pFileName = argv[globalUtilOptind++]; + break; case 'v': fVerbose ^= 1; break; @@ -51774,16 +51783,22 @@ int Abc_CommandAbc9GenHie( Abc_Frame_t * pAbc, int argc, char ** argv ) } } pArgvNew = argv + globalUtilOptind; - nArgcNew = argc - globalUtilOptind; - Gia_GenSandwich( pArgvNew, nArgcNew ); + nArgcNew = argc - globalUtilOptind; + if ( nArgcNew < 1 ) + { + Abc_Print( -1, "Abc_CommandAbc9GenHie(): At least one AIG file should be given on the command line.\n" ); + return 0; + } + Gia_GenSandwich( pArgvNew, nArgcNew, pFileName ); return 0; usage: - Abc_Print( -2, "usage: &gen_hie [-vh] ... \n" ); - Abc_Print( -2, "\t generates a hierarchical design\n" ); - Abc_Print( -2, "\t-v : toggles printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); - Abc_Print( -2, "\t-h : print the command usage\n"); - Abc_Print( -2, "\t : the AIG files for the instance modules\n"); - Abc_Print( -2, "\t (the PO count of should not be less than the PI count of )\n"); + Abc_Print( -2, "usage: &gen_hie [-F ] [-vh] ... \n" ); + Abc_Print( -2, "\t generates a hierarchical design in Verilog\n" ); + Abc_Print( -2, "\t-F : the output file name (optional) [default = \"sandwich.v\"]\n" ); + Abc_Print( -2, "\t-v : toggles printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t : the AIG files for the instance modules\n"); + Abc_Print( -2, "\t (the PO count of should not be less than the PI count of )\n"); return 1;} From 09b0295c1aa288eab59c0041bfd12767949c35c9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 18 Sep 2023 16:27:54 +0800 Subject: [PATCH 13/67] Adding aliases for some commands. --- src/base/abci/abc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 4bb3a43441..5bc50032ce 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -844,14 +844,18 @@ Gia_Man_t * Abc_FrameGetGia( Abc_Frame_t * pAbc ) ***********************************************************************/ void Abc_Init( Abc_Frame_t * pAbc ) { + Cmd_CommandAdd( pAbc, "Printing", "ps", Abc_CommandPrintStats, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_stats", Abc_CommandPrintStats, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_exdc", Abc_CommandPrintExdc, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_io", Abc_CommandPrintIo, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_latch", Abc_CommandPrintLatch, 0 ); + Cmd_CommandAdd( pAbc, "Printing", "pfan", Abc_CommandPrintFanio, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_fanio", Abc_CommandPrintFanio, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_mffc", Abc_CommandPrintMffc, 0 ); + Cmd_CommandAdd( pAbc, "Printing", "pf", Abc_CommandPrintFactor, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_factor", Abc_CommandPrintFactor, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_level", Abc_CommandPrintLevel, 0 ); + Cmd_CommandAdd( pAbc, "Printing", "psu", Abc_CommandPrintSupport, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_supp", Abc_CommandPrintSupport, 0 ); #ifdef ABC_USE_CUDD Cmd_CommandAdd( pAbc, "Printing", "print_mint", Abc_CommandPrintMint, 0 ); @@ -860,6 +864,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Printing", "print_unate", Abc_CommandPrintUnate, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_auto", Abc_CommandPrintAuto, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_kmap", Abc_CommandPrintKMap, 0 ); + Cmd_CommandAdd( pAbc, "Printing", "pg", Abc_CommandPrintGates, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_gates", Abc_CommandPrintGates, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_sharing", Abc_CommandPrintSharing, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_xcut", Abc_CommandPrintXCut, 0 ); @@ -873,9 +878,12 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Printing", "show_bdd", Abc_CommandShowBdd, 0 ); Cmd_CommandAdd( pAbc, "Printing", "show_cut", Abc_CommandShowCut, 0 ); + Cmd_CommandAdd( pAbc, "Synthesis", "clp", Abc_CommandCollapse, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "collapse", Abc_CommandCollapse, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "satclp", Abc_CommandSatClp, 1 ); + Cmd_CommandAdd( pAbc, "Synthesis", "st", Abc_CommandStrash, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "strash", Abc_CommandStrash, 1 ); + Cmd_CommandAdd( pAbc, "Synthesis", "b", Abc_CommandBalance, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "balance", Abc_CommandBalance, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "mux_struct", Abc_CommandMuxStruct, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "multi", Abc_CommandMulti, 1 ); From 7fd4b01fb3e514c9ef2f82ddf7824fb829d84ee1 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 18 Sep 2023 16:30:09 +0800 Subject: [PATCH 14/67] Automatic script file generation. --- src/base/abci/abcPrint.c | 50 +++++++---- src/base/cmd/cmd.c | 173 +++++++++++++++++++++++++++++++++++++-- src/base/io/io.c | 12 +++ 3 files changed, 212 insertions(+), 23 deletions(-) diff --git a/src/base/abci/abcPrint.c b/src/base/abci/abcPrint.c index 7b566b79d7..e90159d2a9 100644 --- a/src/base/abci/abcPrint.c +++ b/src/base/abci/abcPrint.c @@ -224,6 +224,37 @@ float Abc_NtkGetArea( Abc_Ntk_t * pNtk ) return Counter; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float Abc_NtkGetAreaSpecial( Abc_Ntk_t * pNtk ) +{ + Abc_Obj_t * pObj; int i, Count = 0; + Abc_NtkForEachNode( pNtk, pObj, i ) + if ( !strncmp( Mio_GateReadName((Mio_Gate_t*)pObj->pData), "mm", 2 ) ) + Count++; + return 1.0*Count/Abc_NtkNodeNum(pNtk); +} +float Abc_NtkGetAreaSpecial2( Abc_Ntk_t * pNtk ) +{ + Abc_Obj_t * pObj; int i; + float Count = 0, CountAll = 0; + Abc_NtkForEachNode( pNtk, pObj, i ) { + if ( !strncmp( Mio_GateReadName((Mio_Gate_t*)pObj->pData), "mm", 2 ) ) + Count += Mio_GateReadArea((Mio_Gate_t*)pObj->pData); + CountAll += Mio_GateReadArea((Mio_Gate_t*)pObj->pData); + } + return 1.0*Count/CountAll; +} + /**Function************************************************************* Synopsis [Print the vital stats of the network.] @@ -360,7 +391,7 @@ void Abc_NtkPrintStats( Abc_Ntk_t * pNtk, int fFactored, int fSaveBest, int fDum if ( fPrintMem ) Abc_Print( 1," mem =%5.2f MB", Abc_NtkMemory(pNtk)/(1<<20) ); Abc_Print( 1,"\n" ); - +/* // print the statistic into a file if ( fDumpResult ) { @@ -374,6 +405,8 @@ void Abc_NtkPrintStats( Abc_Ntk_t * pNtk, int fFactored, int fSaveBest, int fDum fprintf( pTable, "\n" ); fclose( pTable ); } +*/ + /* { FILE * pTable; @@ -389,21 +422,6 @@ void Abc_NtkPrintStats( Abc_Ntk_t * pNtk, int fFactored, int fSaveBest, int fDum } */ -/* - // print the statistic into a file - { - FILE * pTable; - pTable = fopen( "ucsb/stats.txt", "a+" ); -// fprintf( pTable, "%s ", pNtk->pSpec ); - fprintf( pTable, "%d ", Abc_NtkNodeNum(pNtk) ); -// fprintf( pTable, "%d ", Abc_NtkLevel(pNtk) ); -// fprintf( pTable, "%.0f ", Abc_NtkGetMappedArea(pNtk) ); -// fprintf( pTable, "%.2f ", Abc_NtkDelayTrace(pNtk) ); - fprintf( pTable, "\n" ); - fclose( pTable ); - } -*/ - /* // print the statistic into a file { diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index 67c02cab86..630355fa5a 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -22,6 +22,7 @@ #include #else #include +#include #endif #include "base/abc/abc.h" @@ -54,6 +55,8 @@ static int CmdCommandScanDir ( Abc_Frame_t * pAbc, int argc, char ** argv static int CmdCommandRenameFiles ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandLs ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandScrGen ( Abc_Frame_t * pAbc, int argc, char ** argv ); +#else +static int CmdCommandScrGenLinux ( Abc_Frame_t * pAbc, int argc, char ** argv ); #endif static int CmdCommandVersion ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandSis ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -104,6 +107,8 @@ void Cmd_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Basic", "renamefiles", CmdCommandRenameFiles, 0 ); Cmd_CommandAdd( pAbc, "Basic", "ls", CmdCommandLs, 0 ); Cmd_CommandAdd( pAbc, "Basic", "scrgen", CmdCommandScrGen, 0 ); +#else + Cmd_CommandAdd( pAbc, "Basic", "scrgen", CmdCommandScrGenLinux, 0 ); #endif Cmd_CommandAdd( pAbc, "Basic", "version", CmdCommandVersion, 0 ); @@ -1628,11 +1633,11 @@ int CmdCommandScrGen( Abc_Frame_t * pAbc, int argc, char **argv ) int nFileNameMax, nFileNameCur; int Counter = 0; int fUseCurrent; - char c; + int c; fUseCurrent = 0; Extra_UtilGetoptReset(); - while ( (c = Extra_UtilGetopt(argc, argv, "FDCWch") ) != EOF ) + while ( (c = Extra_UtilGetopt(argc, argv, "FRCWch") ) != EOF ) { switch (c) { @@ -1645,7 +1650,7 @@ int CmdCommandScrGen( Abc_Frame_t * pAbc, int argc, char **argv ) pFileStr = argv[globalUtilOptind]; globalUtilOptind++; break; - case 'D': + case 'R': if ( globalUtilOptind >= argc ) { fprintf( pAbc->Err, "Command line switch \"-D\" should be followed by a string.\n" ); @@ -1795,7 +1800,7 @@ int CmdCommandScrGen( Abc_Frame_t * pAbc, int argc, char **argv ) Line[c] = '/'; fprintf( pFile, "%s", Line ); } - fprintf( pFile, "\n", Line ); + fprintf( pFile, "\n" ); } while( _findnext( hFile, &c_file ) == 0 ); _findclose( hFile ); @@ -1815,17 +1820,171 @@ int CmdCommandScrGen( Abc_Frame_t * pAbc, int argc, char **argv ) return 0; usage: - fprintf( pAbc->Err, "usage: scrgen -F -D -C -W -ch\n" ); + fprintf( pAbc->Err, "usage: scrgen -F -R -C -W -ch\n" ); fprintf( pAbc->Err, "\t generates script for running ABC\n" ); fprintf( pAbc->Err, "\t-F str : the name of the script file [default = \"test.s\"]\n" ); - fprintf( pAbc->Err, "\t-D str : the directory to read files from [default = current]\n" ); + fprintf( pAbc->Err, "\t-R str : the directory to read files from [default = current]\n" ); fprintf( pAbc->Err, "\t-C str : the sequence of commands to run [default = \"ps\"]\n" ); fprintf( pAbc->Err, "\t-W str : the directory to write the resulting files [default = no writing]\n" ); fprintf( pAbc->Err, "\t-c : toggle placing file in current/target dir [default = %s]\n", fUseCurrent? "current": "target" ); fprintf( pAbc->Err, "\t-h : print the command usage\n\n"); - fprintf( pAbc->Err, "\tExample : scrgen -F test1.s -D a/in -C \"ps; st; ps\" -W a/out\n" ); + fprintf( pAbc->Err, "\tExample : scrgen -F test1.s -R a/in -C \"ps; st; ps\" -W a/out\n" ); return 1; } + +#else + +Vec_Ptr_t * CmdReturnFileNames( char * pDirStr ) +{ + Vec_Ptr_t * vRes = Vec_PtrAlloc( 100 ); + struct dirent **namelist; + int num_files = scandir(pDirStr, &namelist, NULL, alphasort); + if (num_files == -1) { + printf("Error opening directory.\n"); + return NULL; + } + for (int i = 0; i < num_files; i++) { + char * pExt = strstr(namelist[i]->d_name, "."); + if ( !pExt || !strcmp(pExt, ".") || !strcmp(pExt, "..") || !strcmp(pExt, ".s") || !strcmp(pExt, ".txt") ) + continue; + Vec_PtrPush( vRes, Abc_UtilStrsav(namelist[i]->d_name) ); + free(namelist[i]); + } + free(namelist); + return vRes; +} + +int CmdCommandScrGenLinux( Abc_Frame_t * pAbc, int argc, char **argv ) +{ + Vec_Ptr_t * vNames = NULL; + FILE * pFile = NULL; + char * pFileStr = (char *)"test.s"; + char * pDirStr = (char *)"."; + char * pComStr = (char *)"ps"; + char * pWriteStr = NULL; + char * pWriteExt = NULL; + char Line[2000], * pName; + int nFileNameMax; + int c, k; + + Extra_UtilGetoptReset(); + while ( (c = Extra_UtilGetopt(argc, argv, "FRCWEh") ) != EOF ) + { + switch (c) + { + case 'F': + if ( globalUtilOptind >= argc ) + { + fprintf( pAbc->Err, "Command line switch \"-F\" should be followed by a string.\n" ); + goto usage; + } + pFileStr = argv[globalUtilOptind]; + globalUtilOptind++; + break; + case 'R': + if ( globalUtilOptind >= argc ) + { + fprintf( pAbc->Err, "Command line switch \"-D\" should be followed by a string.\n" ); + goto usage; + } + pDirStr = argv[globalUtilOptind]; + globalUtilOptind++; + break; + case 'C': + if ( globalUtilOptind >= argc ) + { + fprintf( pAbc->Err, "Command line switch \"-C\" should be followed by a string.\n" ); + goto usage; + } + pComStr = argv[globalUtilOptind]; + globalUtilOptind++; + break; + case 'W': + if ( globalUtilOptind >= argc ) + { + fprintf( pAbc->Err, "Command line switch \"-W\" should be followed by a string.\n" ); + goto usage; + } + pWriteStr = argv[globalUtilOptind]; + globalUtilOptind++; + break; + case 'E': + if ( globalUtilOptind >= argc ) + { + fprintf( pAbc->Err, "Command line switch \"-E\" should be followed by a string.\n" ); + goto usage; + } + pWriteExt = argv[globalUtilOptind]; + globalUtilOptind++; + break; + default: + goto usage; + } + } + pFile = fopen( pFileStr, "w" ); + if ( pFile == NULL ) + { + printf( "Cannot open output file %s.\n", pFileStr ); + return 0; + } + vNames = CmdReturnFileNames( pDirStr ); + if ( !vNames || !Vec_PtrSize(vNames) ) + { + if ( vNames ) + printf( "It looks like the directory \"%s\" does not contain any relevant files.\n", pDirStr ); + Vec_PtrFreeP(&vNames); + return 0; + } + nFileNameMax = 0; + Vec_PtrForEachEntry( char *, vNames, pName, k ) + if ( nFileNameMax < strlen(pName) ) + nFileNameMax = strlen(pName); + { + int fAndSpace = pComStr[0] == '&'; + fprintf( pFile, "# Script file produced by ABC on %s\n", Extra_TimeStamp() ); + fprintf( pFile, "# Command line was: scrgen -F %s -D %s -C \"%s\"%s%s%s%s\n", + pFileStr, pDirStr, pComStr, + pWriteStr?" -W ":"", pWriteStr?pWriteStr:"", + pWriteExt?" -E ":"", pWriteExt?pWriteExt:"" ); + Vec_PtrForEachEntry( char *, vNames, pName, k ) { + char * pExt = strstr(pName, "."); + if ( !pExt || !strcmp(pExt, ".") || !strcmp(pExt, "..") || !strcmp(pExt, ".s") || !strcmp(pExt, ".txt") ) + continue; + sprintf( Line, "%sread %s%s%-*s ; %s", fAndSpace ? "&" : "", pDirStr?pDirStr:"", pDirStr?"/":"", nFileNameMax, pName, pComStr ); + for ( c = (int)strlen(Line)-1; c >= 0; c-- ) + if ( Line[c] == '\\' ) + Line[c] = '/'; + fprintf( pFile, "%s", Line ); + if ( pWriteStr ) + { + char * pFNameOut = pWriteExt ? Extra_FileNameGenericAppend(pName, pWriteExt) : pName; + sprintf( Line, " ; %swrite %s/%-*s", fAndSpace ? "&" : "", pWriteStr, nFileNameMax, pFNameOut ); + for ( c = (int)strlen(Line)-1; c >= 0; c-- ) + if ( Line[c] == '\\' ) + Line[c] = '/'; + fprintf( pFile, "%s", Line ); + } + fprintf( pFile, "\n" ); + } + } + fclose( pFile ); + printf( "Script file \"%s\" with command lines for %d files.\n", pFileStr, Vec_PtrSize(vNames) ); + Vec_PtrFreeFree( vNames ); + return 0; + +usage: + fprintf( pAbc->Err, "usage: scrgen -F -R -C -W -E -h\n" ); + fprintf( pAbc->Err, "\t generates script for running ABC\n" ); + fprintf( pAbc->Err, "\t-F str : the name of the script file [default = \"test.s\"]\n" ); + fprintf( pAbc->Err, "\t-R str : the directory to read files from [default = current]\n" ); + fprintf( pAbc->Err, "\t-C str : the sequence of commands to run [default = \"ps\"]\n" ); + fprintf( pAbc->Err, "\t-W str : the directory to write the resulting files [default = no writing]\n" ); + fprintf( pAbc->Err, "\t-E str : the output files extension (with \".\") [default = the same as input files]\n" ); + fprintf( pAbc->Err, "\t-h : print the command usage\n\n"); + fprintf( pAbc->Err, "\tExample : scrgen -F test1.s -R a/in -C \"ps; st; ps\" -W a/out -E .blif\n" ); + return 1; +} + #endif diff --git a/src/base/io/io.c b/src/base/io/io.c index 7b8ca184e6..e808d1d0b0 100644 --- a/src/base/io/io.c +++ b/src/base/io/io.c @@ -276,6 +276,18 @@ int IoCommandRead( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; } // read the file using the corresponding file reader + if ( strstr(pFileName, ".") && !strcmp(strstr(pFileName, "."), ".s") ) + { + char Command[1000]; + assert( strlen(pFileName) < 980 ); + sprintf( Command, "source -x %s", pFileName ); + if ( Cmd_CommandExecute( pAbc, Command ) ) + { + fprintf( stdout, "Cannot execute command \"%s\".\n", Command ); + return 1; + } + return 0; + } pNtk = Io_Read( pFileName, Io_ReadFileType(pFileName), fCheck, fBarBufs ); if ( pNtk == NULL ) return 0; From 73dac01c15e55026ef057fcc0d08a8b77799a8bb Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 21 Sep 2023 11:08:16 +0800 Subject: [PATCH 15/67] Warning regarding PathMatchSpec() on Windows. --- src/map/scl/sclLiberty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/scl/sclLiberty.c b/src/map/scl/sclLiberty.c index 674f655493..3d62b68e55 100644 --- a/src/map/scl/sclLiberty.c +++ b/src/map/scl/sclLiberty.c @@ -83,7 +83,7 @@ struct Scl_Tree_t_ static inline int Scl_LibertyGlobMatch(const char * pattern, const char * string) { #ifdef _WIN32 - return PathMatchSpec(string, pattern); + return PathMatchSpec(string, pattern); // if the compiler complains, add "-lshlwapi" #else return fnmatch(pattern, string, 0) == 0; #endif From 4d1618f600a82f817ab41141446132d73aacd3c7 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 21 Sep 2023 11:08:43 +0800 Subject: [PATCH 16/67] Enable dumping Verilog with assign-statements. --- src/aig/gia/gia.h | 2 +- src/aig/gia/giaMan.c | 311 +++++++++++++++++++++++++++++++++++++++++-- src/base/abci/abc.c | 13 +- 3 files changed, 312 insertions(+), 14 deletions(-) diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index dab6770bb5..654f2faa5c 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -1530,7 +1530,7 @@ extern void Gia_ManPrintStatsMiter( Gia_Man_t * p, int fVerbose ) extern void Gia_ManSetRegNum( Gia_Man_t * p, int nRegs ); extern void Gia_ManReportImprovement( Gia_Man_t * p, Gia_Man_t * pNew ); extern void Gia_ManPrintNpnClasses( Gia_Man_t * p ); -extern void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb ); +extern void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb, int fAssign ); /*=== giaMem.c ===========================================================*/ extern Gia_MmFixed_t * Gia_MmFixedStart( int nEntrySize, int nEntriesMax ); extern void Gia_MmFixedStop( Gia_MmFixed_t * p, int fVerbose ); diff --git a/src/aig/gia/giaMan.c b/src/aig/gia/giaMan.c index 2449b5df75..e771f99cc4 100644 --- a/src/aig/gia/giaMan.c +++ b/src/aig/gia/giaMan.c @@ -1408,7 +1408,32 @@ void Gia_ManWriteNames( FILE * pFile, char c, int n, Vec_Ptr_t * vNames, int Sta fFirst = 0; } } -void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb ) +void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb, int fAssign ) +{ + if ( fInterComb ) + { + if ( fAssign ) { + extern void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName ); + Gia_ManDumpInterfaceAssign( p, pFileName ); + } + else { + extern void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ); + Gia_ManDumpInterface( p, pFileName ); + } + } + else + { + if ( fAssign ) { + extern void Gia_ManDumpVerilogNoInterAssign( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter ); + Gia_ManDumpVerilogNoInterAssign( p, pFileName, vObjs, fVerBufs, fInter ); + } + else { + extern void Gia_ManDumpVerilogNoInter( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter ); + Gia_ManDumpVerilogNoInter( p, pFileName, vObjs, fVerBufs, fInter ); + } + } +} +void Gia_ManDumpVerilogNoInter( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter ) { Gia_Obj_t * pObj; Vec_Bit_t * vInvs, * vUsed; @@ -1416,13 +1441,6 @@ void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int int nDigitsI = Abc_Base10Log( Gia_ManPiNum(p) ); int nDigitsO = Abc_Base10Log( Gia_ManPoNum(p) ); int i, k, iObj, nRegs = Gia_ManRegNum(p); - if ( fInterComb ) - { - extern void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ); - Gia_ManDumpInterface( p, pFileName ); - return; - } - FILE * pFile = fopen( pFileName, "wb" ); if ( pFile == NULL ) { @@ -1595,6 +1613,179 @@ void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int Gia_ManSetRegNum( p, nRegs ); } +void Gia_ManDumpVerilogNoInterAssign( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter ) +{ + Gia_Obj_t * pObj; + Vec_Bit_t * vInvs, * vUsed; + int nDigits = Abc_Base10Log( Gia_ManObjNum(p) ); + int nDigitsI = Abc_Base10Log( Gia_ManPiNum(p) ); + int nDigitsO = Abc_Base10Log( Gia_ManPoNum(p) ); + int i, k, iObj, nRegs = Gia_ManRegNum(p); + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + { + printf( "Cannot open output file \"%s\".\n", pFileName ); + return; + } + + if ( fInter || nRegs ) + Gia_ManDumpInterface2( p, pFile ); + //Gia_ManSetRegNum( p, 0 ); + p->nRegs = 0; + + vInvs = Gia_ManGenUsed( p, 0 ); + vUsed = Gia_ManGenUsed( p, 1 ); + + //fprintf( pFile, "// This Verilog file is written by ABC on %s\n\n", Extra_TimeStamp() ); + + fprintf( pFile, "module " ); + Gia_ManDumpModuleName( pFile, p->pName ); + + if ( fVerBufs ) + { + fprintf( pFile, " (\n " ); + Gia_ManWriteNames( pFile, 'a', Gia_ManPiNum(p), NULL, 4, 4, NULL ); + fprintf( pFile, ",\n " ); + + Gia_ManWriteNames( pFile, 'y', Gia_ManPoNum(p), NULL, 4, 4, NULL ); + fprintf( pFile, "\n );\n\n" ); + + fprintf( pFile, " input " ); + Gia_ManWriteNames( pFile, 'a', Gia_ManPiNum(p), NULL, 8, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " output " ); + Gia_ManWriteNames( pFile, 'y', Gia_ManPoNum(p), NULL, 9, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 8, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 9, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + Gia_ManForEachPi( p, pObj, i ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) ); + fprintf( pFile, " %s;\n", Gia_ObjGetDumpName(NULL, 'a', i, nDigitsI) ); + } + fprintf( pFile, "\n" ); + + Gia_ManForEachPo( p, pObj, i ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'y', i, nDigitsO) ); + fprintf( pFile, " %s;\n", Gia_ObjGetDumpName(p->vNamesOut, 'z', i, nDigitsO) ); + } + fprintf( pFile, "\n" ); + } + else + { + fprintf( pFile, " (\n " ); + Gia_ManWriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 4, 4, NULL ); + fprintf( pFile, ",\n " ); + + Gia_ManWriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 4, 4, NULL ); + fprintf( pFile, "\n );\n\n" ); + + fprintf( pFile, " input " ); + Gia_ManWriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 8, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " output " ); + Gia_ManWriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 9, 4, NULL ); + fprintf( pFile, ";\n\n" ); + } + + if ( Vec_BitCount(vUsed) ) + { + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'n', Gia_ManObjNum(p), NULL, 7, 4, vUsed ); + fprintf( pFile, ";\n\n" ); + } + + if ( Vec_BitCount(vInvs) ) + { + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'i', Gia_ManObjNum(p), NULL, 7, 4, vInvs ); + fprintf( pFile, ";\n\n" ); + } + + if ( vObjs ) + { + fprintf( pFile, " wire " ); + Vec_IntForEachEntry( vObjs, iObj, i ) + fprintf( pFile, " t_%d%s", i, i==Vec_IntSize(vObjs)-1 ? "" : "," ); + fprintf( pFile, ";\n\n" ); + Vec_IntForEachEntry( vObjs, iObj, i ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'n', iObj, nDigits) ); + fprintf( pFile, " t_%d;\n", i ); + } + fprintf( pFile, "\n" ); + } + + // input inverters + Gia_ManForEachPi( p, pObj, i ) + { + if ( Vec_BitEntry(vUsed, Gia_ObjId(p, pObj)) ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'n', Gia_ObjId(p, pObj), nDigits) ); + fprintf( pFile, " %s;\n", Gia_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) ); + } + if ( Vec_BitEntry(vInvs, Gia_ObjId(p, pObj)) ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'i', Gia_ObjId(p, pObj), nDigits) ); + fprintf( pFile, " ~%s;\n", Gia_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) ); + } + } + + // internal nodes and their inverters + fprintf( pFile, "\n" ); + Gia_ManForEachAnd( p, pObj, i ) + { + int fSkip = 0; + if ( vObjs ) + { + Vec_IntForEachEntry( vObjs, iObj, k ) + if ( iObj == i ) + break; + if ( k < Vec_IntSize(vObjs) ) + fSkip = 1; + } + if ( !fSkip ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'n', i, nDigits) ); + fprintf( pFile, " %s &", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0(pObj, i), nDigits) ); + fprintf( pFile, " %s;\n", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC1(pObj)? 'i':'n'), Gia_ObjFaninId1(pObj, i), nDigits) ); + } + if ( Vec_BitEntry(vInvs, i) ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'i', i, nDigits) ); + fprintf( pFile, " ~%s;\n", Gia_ObjGetDumpName(NULL, 'n', i, nDigits) ); + } + } + + // output drivers + fprintf( pFile, "\n" ); + Gia_ManForEachPo( p, pObj, i ) + { + fprintf( pFile, " assign %s = ", Gia_ObjGetDumpName(p->vNamesOut, 'z', i, nDigitsO) ); + if ( Gia_ObjIsConst0(Gia_ObjFanin0(pObj)) ) + fprintf( pFile, "1\'b%d;\n", Gia_ObjFaninC0(pObj) ); + else + fprintf( pFile, "%s;\n", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0p(p, pObj), nDigits) ); + } + + fprintf( pFile, "\nendmodule\n\n" ); + fclose( pFile ); + + Vec_BitFree( vInvs ); + Vec_BitFree( vUsed ); + + Gia_ManSetRegNum( p, nRegs ); +} /**Function************************************************************* @@ -1709,6 +1900,108 @@ void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ) Vec_BitFree( vInvs ); Vec_BitFree( vUsed ); } +void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName ) +{ + Gia_Obj_t * pObj; + Vec_Bit_t * vInvs, * vUsed; + int nDigits = Abc_Base10Log( Gia_ManObjNum(p) ); + int nDigitsI = Abc_Base10Log( Gia_ManPiNum(p) ); + int nDigitsO = Abc_Base10Log( Gia_ManPoNum(p) ); + int i; + + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + { + printf( "Cannot open output file \"%s\".\n", pFileName ); + return; + } + + vInvs = Gia_ManGenUsed( p, 0 ); + vUsed = Gia_ManGenUsed( p, 1 ); + + fprintf( pFile, "module " ); + Gia_ManDumpModuleName( pFile, p->pName ); + fprintf( pFile, "_wrapper" ); + fprintf( pFile, " ( _i_, _o_ );\n\n" ); + fprintf( pFile, " input [%d:0] _i_;\n", Gia_ManCiNum(p)-1 ); + fprintf( pFile, " output [%d:0] _o_;\n\n", Gia_ManCoNum(p)-1 ); + + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 8, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 9, 4, NULL ); + fprintf( pFile, ";\n\n" ); + + fprintf( pFile, " assign { " ); + Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, NULL ); + fprintf( pFile, " } = _i_;\n\n" ); + + fprintf( pFile, " assign _o_ = { " ); + Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, NULL ); + fprintf( pFile, " };\n\n" ); + + if ( Vec_BitCount(vUsed) ) + { + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'n', Gia_ManObjNum(p), NULL, 7, 4, vUsed ); + fprintf( pFile, ";\n\n" ); + } + + if ( Vec_BitCount(vInvs) ) + { + fprintf( pFile, " wire " ); + Gia_ManWriteNames( pFile, 'i', Gia_ManObjNum(p), NULL, 7, 4, vInvs ); + fprintf( pFile, ";\n\n" ); + } + + // input inverters + Gia_ManForEachCi( p, pObj, i ) + { + if ( Vec_BitEntry(vUsed, Gia_ObjId(p, pObj)) ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'n', Gia_ObjId(p, pObj), nDigits) ); + fprintf( pFile, " %s;\n", Gia_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) ); + } + if ( Vec_BitEntry(vInvs, Gia_ObjId(p, pObj)) ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'i', Gia_ObjId(p, pObj), nDigits) ); + fprintf( pFile, " ~%s;\n", Gia_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) ); + } + } + + // internal nodes and their inverters + fprintf( pFile, "\n" ); + Gia_ManForEachAnd( p, pObj, i ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'n', i, nDigits) ); + fprintf( pFile, " %s &", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0(pObj, i), nDigits) ); + fprintf( pFile, " %s;\n", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC1(pObj)? 'i':'n'), Gia_ObjFaninId1(pObj, i), nDigits) ); + if ( Vec_BitEntry(vInvs, i) ) + { + fprintf( pFile, " assign %s =", Gia_ObjGetDumpName(NULL, 'i', i, nDigits) ); + fprintf( pFile, " ~%s;\n", Gia_ObjGetDumpName(NULL, 'n', i, nDigits) ); + } + } + + // output drivers + fprintf( pFile, "\n" ); + Gia_ManForEachCo( p, pObj, i ) + { + fprintf( pFile, " assign %s = ", Gia_ObjGetDumpName(p->vNamesOut, 'z', i, nDigitsO) ); + if ( Gia_ObjIsConst0(Gia_ObjFanin0(pObj)) ) + fprintf( pFile, "1\'b%d;\n", Gia_ObjFaninC0(pObj) ); + else + fprintf( pFile, "%s;\n", Gia_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0p(p, pObj), nDigits) ); + } + + fprintf( pFile, "\nendmodule\n\n" ); + fclose( pFile ); + + Vec_BitFree( vInvs ); + Vec_BitFree( vUsed ); +} /**Function************************************************************* @@ -1783,7 +2076,7 @@ void Gia_GenSandwich( char ** pFNames, int nFNames, char * pFileName ) fprintf( pFile, "endmodule\n" ); fclose( pFile ); for ( i = 0; i < nFNames; i++ ) { - Gia_ManDumpVerilog( pGias[i], Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v"), NULL, 0, 0, 1 ); + Gia_ManDumpVerilog( pGias[i], Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v"), NULL, 0, 0, 1, 0 ); printf( "Dumped Verilog file \"%s\"\n", Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v") ); } Gia_FreeMany( pGias, nFNames ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 5bc50032ce..4ee12db274 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -31938,13 +31938,14 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) int fVerilog = 0; int fInter = 0; int fInterComb = 0; + int fAssign = 0; int fVerBufs = 0; int fMiniAig = 0; int fMiniLut = 0; int fWriteNewLine = 0; int fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "upicbmlnvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "upicabmlnvh" ) ) != EOF ) { switch ( c ) { @@ -31959,7 +31960,10 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) break; case 'c': fInterComb ^= 1; - break; + break; + case 'a': + fAssign ^= 1; + break; case 'b': fVerBufs ^= 1; break; @@ -32001,7 +32005,7 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) Gia_ManStop( pGia ); } else if ( fVerilog ) - Gia_ManDumpVerilog( pAbc->pGia, pFileName, NULL, fVerBufs, fInter, fInterComb ); + Gia_ManDumpVerilog( pAbc->pGia, pFileName, NULL, fVerBufs, fInter, fInterComb, fAssign ); else if ( fMiniAig ) Gia_ManWriteMiniAig( pAbc->pGia, pFileName ); else if ( fMiniLut ) @@ -32011,12 +32015,13 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &w [-upicbmlnvh] \n" ); + Abc_Print( -2, "usage: &w [-upicabmlnvh] \n" ); Abc_Print( -2, "\t writes the current AIG into the AIGER file\n" ); Abc_Print( -2, "\t-u : toggle writing canonical AIG structure [default = %s]\n", fUnique? "yes" : "no" ); Abc_Print( -2, "\t-p : toggle writing Verilog with 'and' and 'not' [default = %s]\n", fVerilog? "yes" : "no" ); Abc_Print( -2, "\t-i : toggle writing the interface module in Verilog [default = %s]\n", fInter? "yes" : "no" ); Abc_Print( -2, "\t-c : toggle writing the interface module in Verilog [default = %s]\n", fInterComb? "yes" : "no" ); + Abc_Print( -2, "\t-a : toggle writing the interface module with assign-statements [default = %s]\n", fAssign? "yes" : "no" ); Abc_Print( -2, "\t-b : toggle writing additional buffers in Verilog [default = %s]\n", fVerBufs? "yes" : "no" ); Abc_Print( -2, "\t-m : toggle writing MiniAIG rather than AIGER [default = %s]\n", fMiniAig? "yes" : "no" ); Abc_Print( -2, "\t-l : toggle writing MiniLUT rather than AIGER [default = %s]\n", fMiniLut? "yes" : "no" ); From 0f11580fcec78fab2e70960b330faa3bf5e6d1fe Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 24 Sep 2023 22:18:45 +0800 Subject: [PATCH 17/67] Experiments with retiming. --- src/aig/gia/giaMini.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/aig/gia/giaMini.c b/src/aig/gia/giaMini.c index 85647eac51..9b679af904 100644 --- a/src/aig/gia/giaMini.c +++ b/src/aig/gia/giaMini.c @@ -1257,7 +1257,7 @@ Vec_Str_t * Gia_ManRetimableF( Gia_Man_t * p, int * pRst, int * pSet, int * pEna int * pNode = Vec_IntEntryP( vTemps, 3*i ); pStops[i] = (char)1; if ( pFan0[0] != -1 && pFan0[0] == pFan1[0] && pFan0[1] == pFan1[1] && pFan0[2] == pFan1[2] ) - pStops[i] = (char)0, pNode[0] = pFan0[0], pNode[1] = pFan0[1], pNode[2] = pFan0[2]; + pStops[i] = (char)0, pNode[0] = pFan0[0], pNode[1] = pFan0[1], pNode[2] = pFan0[2]; } Vec_IntFree( vTemps ); return vStops; @@ -1266,32 +1266,37 @@ Vec_Str_t * Gia_ManRetimableB( Gia_Man_t * p, int * pRst, int * pSet, int * pEna { Vec_Str_t * vStops = Vec_StrStart( Gia_ManObjNum(p) ); Vec_Int_t * vTemps = Vec_IntStartFull( 3*Gia_ManObjNum(p) ); - Gia_Obj_t * pObj, * pObjRi, * pObjRo; int i, n; + Gia_Obj_t * pObj, * pObjRi, * pObjRo; int i, n, iFanout; char * pStops = Vec_StrArray(vStops); assert( Gia_ManRegNum(p) > 0 ); Gia_ManForEachRiRo( p, pObjRi, pObjRo, i ) { - Vec_IntWriteEntry( vTemps, 3*Gia_ObjFaninId0p(p, pObjRi) + 0, pRst[i] ); - Vec_IntWriteEntry( vTemps, 3*Gia_ObjFaninId0p(p, pObjRi) + 1, pSet[i] ); - Vec_IntWriteEntry( vTemps, 3*Gia_ObjFaninId0p(p, pObjRi) + 2, pEna[i] ); + Vec_IntWriteEntry( vTemps, 3*Gia_ObjId(p, pObjRi) + 0, pRst[i] ); + Vec_IntWriteEntry( vTemps, 3*Gia_ObjId(p, pObjRi) + 1, pSet[i] ); + Vec_IntWriteEntry( vTemps, 3*Gia_ObjId(p, pObjRi) + 2, pEna[i] ); } + Gia_ManStaticFanoutStart( p ); Gia_ManForEachAndReverse( p, pObj, i ) { - int iFans[2] = { Gia_ObjFaninId0(pObj, i), Gia_ObjFaninId1(pObj, i) }; - int * pFans[2] = { Vec_IntEntryP( vTemps, 3*iFans[0] ), Vec_IntEntryP( vTemps, 3*iFans[1] ) }; + int * pFan0 = Vec_IntEntryP( vTemps, 3*Gia_ObjFanoutId(p, i, 0) ); int * pNode = Vec_IntEntryP( vTemps, 3*i ); - if ( pNode[0] == -1 ) + pStops[i] = (char)1; + if ( pFan0[0] == -1 ) continue; - for ( n = 0; n < 2; n++ ) - if ( pFans[n][0] == -1 ) - pStops[iFans[n]] = (char)1, pFans[n][0] = pNode[0], pFans[n][1] = pNode[1], pFans[n][2] = pNode[2]; - else if ( pFans[n][0] != pNode[0] || pFans[n][1] != pNode[1] || pFans[n][2] != pNode[2] ) - pStops[iFans[n]] = (char)0; + Gia_ObjForEachFanoutStaticId( p, i, iFanout, n ) { + int * pFan1 = Vec_IntEntryP( vTemps, 3*iFanout ); + if ( pFan1[0] == -1 || pFan0[0] != pFan1[0] || pFan0[1] != pFan1[1] || pFan0[2] != pFan1[2] ) + break; + } + if ( n < Gia_ObjFanoutNum(p, pObj) ) + continue; + pStops[i] = (char)0, pNode[0] = pFan0[0], pNode[1] = pFan0[1], pNode[2] = pFan0[2]; } - pStops[0] = (char)0; - Gia_ManForEachCi( p, pObj, i ) - pStops[Gia_ObjId(p, pObj)] = (char)0; - Gia_ManForEachAnd( p, pObj, i ) - pStops[i] = (char)!pStops[i]; - Vec_IntFree( vTemps ); + Gia_ManStaticFanoutStop( p ); + Vec_IntFree( vTemps ); + Gia_ManForEachRiRo( p, pObjRi, pObjRo, i ) { + if ( Gia_ObjIsAnd(Gia_ManObj(p, Abc_Lit2Var(pRst[i]))) ) pStops[Abc_Lit2Var(pRst[i])] = 1; + if ( Gia_ObjIsAnd(Gia_ManObj(p, Abc_Lit2Var(pSet[i]))) ) pStops[Abc_Lit2Var(pSet[i])] = 1; + if ( Gia_ObjIsAnd(Gia_ManObj(p, Abc_Lit2Var(pEna[i]))) ) pStops[Abc_Lit2Var(pEna[i])] = 1; + } return vStops; } From cc636a0d8390cb54ed2abad393c297d63e1ba52f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 28 Sep 2023 06:40:57 -0700 Subject: [PATCH 18/67] Experiments with verification. --- src/base/abci/abc.c | 85 ++++++++++++++++ src/proof/cec/cecProve.c | 205 ++++++++++++++++++++++++++++++++++++++ src/proof/cec/module.make | 1 + 3 files changed, 291 insertions(+) create mode 100644 src/proof/cec/cecProve.c diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 4ee12db274..586ac2c57e 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -541,6 +541,7 @@ static int Abc_CommandAbc9PoPart ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9GroupProve ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9MultiProve ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9SplitProve ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9SProve ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9SplitSat ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Bmc ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9SBmc ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1314,6 +1315,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&gprove", Abc_CommandAbc9GroupProve, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&mprove", Abc_CommandAbc9MultiProve, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&splitprove", Abc_CommandAbc9SplitProve, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&sprove", Abc_CommandAbc9SProve, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&splitsat", Abc_CommandAbc9SplitSat, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&bmc", Abc_CommandAbc9Bmc, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&bmcs", Abc_CommandAbc9SBmc, 0 ); @@ -46278,6 +46280,89 @@ int Abc_CommandAbc9SplitProve( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int fVerbose, int fVeryVerbose, int fSilent ); + int c, nProcs = 5, nTimeOut = 3, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "PTsvwh" ) ) != EOF ) + { + switch ( c ) + { + case 'P': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-P\" should be followed by a positive integer.\n" ); + goto usage; + } + nProcs = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nProcs <= 0 ) + goto usage; + break; + case 'T': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-T\" should be followed by a positive integer.\n" ); + goto usage; + } + nTimeOut = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nTimeOut <= 0 ) + goto usage; + break; + case 's': + fSilent ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'w': + fVeryVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9SProve(): There is no AIG.\n" ); + return 1; + } + if ( Gia_ManRegNum(pAbc->pGia) == 0 ) + { + Abc_Print( -1, "Abc_CommandAbc9SProve(): The problem is combinational.\n" ); + return 1; + } + pAbc->Status = Cec_GiaProveTest( pAbc->pGia, nProcs, nTimeOut, fVerbose, fVeryVerbose, fSilent ); + Abc_FrameReplaceCex( pAbc, &pAbc->pGia->pCexSeq ); + return 0; + +usage: + Abc_Print( -2, "usage: &sprove [-PT num] [-svwh]\n" ); + Abc_Print( -2, "\t proves CEC problem by case-splitting\n" ); + Abc_Print( -2, "\t-P num : the number of concurrent processes [default = %d]\n", nProcs ); + Abc_Print( -2, "\t-T num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut ); + Abc_Print( -2, "\t-s : enable silent computation (no reporting) [default = %s]\n", fSilent? "yes": "no" ); + 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"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c new file mode 100644 index 0000000000..748f506f91 --- /dev/null +++ b/src/proof/cec/cecProve.c @@ -0,0 +1,205 @@ +/**CFile**************************************************************** + + FileName [cecSplit.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Combinational equivalence checking.] + + Synopsis [Cofactoring for combinational miters.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: cecSplit.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include +#include "aig/gia/gia.h" +#include "aig/gia/giaAig.h" + + +#ifdef ABC_USE_PTHREADS + +#ifdef _WIN32 +#include "../lib/pthread.h" +#else +#include +#include +#endif + +#endif + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#ifndef ABC_USE_PTHREADS + +int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int fVerbose, int fVeryVerbose, int fSilent ) { return -1; } + +#else // pthreads are used + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, Abc_Cex_t ** ppCex ) +{ + abctime clk = Abc_Clock(); + //abctime clkStop = nTimeOut * CLOCKS_PER_SEC + Abc_Clock(); + printf( "Calling engine %d with timeout %d sec.\n", iEngine, nTimeOut ); + if ( iEngine == 0 ) + { + } + else if ( iEngine == 1 ) + { + } + else if ( iEngine == 2 ) + { + } + else if ( iEngine == 3 ) + { + } + else assert( 0 ); + //while ( Abc_Clock() < clkStop ); + printf( "Engine %d finished. ", iEngine ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + return 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +#define PAR_THR_MAX 8 +typedef struct Par_ThData_t_ +{ + Gia_Man_t * p; + Abc_Cex_t * pCex; + int iEngine; + int fWorking; + int nTimeOut; + int Result; +} Par_ThData_t; +void * Cec_GiaProveWorkerThread( void * pArg ) +{ + Par_ThData_t * pThData = (Par_ThData_t *)pArg; + volatile int * pPlace = &pThData->fWorking; + while ( 1 ) + { + while ( *pPlace == 0 ); + assert( pThData->fWorking ); + if ( pThData->p == NULL ) + { + pthread_exit( NULL ); + assert( 0 ); + return NULL; + } + pThData->Result = Cec_GiaProveOne( pThData->p, pThData->iEngine, pThData->nTimeOut, &pThData->pCex ); + pThData->fWorking = 0; + } + assert( 0 ); + return NULL; +} +int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int fVerbose, int fVeryVerbose, int fSilent ) +{ + abctime clkTotal = Abc_Clock(); + Par_ThData_t ThData[PAR_THR_MAX]; + pthread_t WorkerThread[PAR_THR_MAX]; + int i, status, RetValue = -1; + Abc_CexFreeP( &p->pCexComb ); + Abc_CexFreeP( &p->pCexSeq ); + if ( fVerbose ) + printf( "Solving verification problem with the following parameters:\n" ); + if ( fVerbose ) + printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", nProcs, nTimeOut, fVerbose ); + fflush( stdout ); + if ( nProcs == 1 ) + return -1; + // subtract manager thread + nProcs--; + assert( (nProcs == 4 || nProcs == 8) && nProcs <= PAR_THR_MAX ); + // start threads + for ( i = 0; i < nProcs; i++ ) + { + ThData[i].p = Gia_ManDup(p); + ThData[i].pCex = NULL; + ThData[i].iEngine = i; + ThData[i].nTimeOut = nTimeOut; + ThData[i].fWorking = 0; + ThData[i].Result = -1; + status = pthread_create( WorkerThread + i, NULL,Cec_GiaProveWorkerThread, (void *)(ThData + i) ); assert( status == 0 ); + } + + for ( i = 0; i < nProcs; i++ ) + ThData[i].fWorking = 1; + + // wait till threads finish + for ( i = 0; i < nProcs; i++ ) + if ( ThData[i].fWorking ) + i = -1; + + // stop threads + for ( i = 0; i < nProcs; i++ ) + { + assert( !ThData[i].fWorking ); + // cleanup + Gia_ManStopP( &ThData[i].p ); + if ( !p->pCexSeq && ThData[i].pCex ) + p->pCexSeq = Abc_CexDup( ThData[i].pCex, -1 ); + Abc_CexFreeP( &ThData[i].pCex ); + // stop + ThData[i].p = NULL; + ThData[i].fWorking = 1; + } + if ( !fSilent ) + { + if ( RetValue == 0 ) + printf( "Problem is SAT " ); + else if ( RetValue == 1 ) + printf( "Problem is UNSAT " ); + else if ( RetValue == -1 ) + printf( "Problem is UNDECIDED " ); + else assert( 0 ); + printf( ". " ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clkTotal ); + fflush( stdout ); + } + return RetValue; +} + +#endif // pthreads are used + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/proof/cec/module.make b/src/proof/cec/module.make index ed3dac110e..ed8deba98d 100644 --- a/src/proof/cec/module.make +++ b/src/proof/cec/module.make @@ -6,6 +6,7 @@ SRC += src/proof/cec/cecCec.c \ src/proof/cec/cecIso.c \ src/proof/cec/cecMan.c \ src/proof/cec/cecPat.c \ + src/proof/cec/cecProve.c \ src/proof/cec/cecSat.c \ src/proof/cec/cecSatG.c \ src/proof/cec/cecSatG2.c \ From d971e3ecffd89800b95e82ff22eb294cc421599b Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 28 Sep 2023 07:17:42 -0700 Subject: [PATCH 19/67] Updating windows project file. --- abclib.dsp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/abclib.dsp b/abclib.dsp index 7433c51394..3255424dbb 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -5627,6 +5627,10 @@ SOURCE=.\src\proof\cec\cecPat.c # End Source File # Begin Source File +SOURCE=.\src\proof\cec\cecProve.c +# End Source File +# Begin Source File + SOURCE=.\src\proof\cec\cecSat.c # End Source File # Begin Source File From 65ccd3cc692d2a7976d7d57954bc2572ddb9c9c9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 29 Sep 2023 16:07:29 -0700 Subject: [PATCH 20/67] Enabled literal remapping. --- src/aig/gia/giaMini.c | 30 +++++++++++++++++++++++++++--- src/base/main/abcapis.h | 2 +- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/aig/gia/giaMini.c b/src/aig/gia/giaMini.c index 9b679af904..2fce5d0d44 100644 --- a/src/aig/gia/giaMini.c +++ b/src/aig/gia/giaMini.c @@ -1311,18 +1311,42 @@ Vec_Str_t * Gia_ManRetimableB( Gia_Man_t * p, int * pRst, int * pSet, int * pEna SeeAlso [] ***********************************************************************/ -void Abc_FrameSetRetimingData( Abc_Frame_t * pAbc, int * pRst, int * pSet, int * pEna ) +void Abc_FrameRemapLits( int * pLits, int nLits, Vec_Int_t * vMap ) +{ + for ( int i = 0; i < nLits; i++ ) + pLits[i] = Abc_Lit2LitL( Vec_IntArray(vMap), pLits[i] ); +} +void Abc_FrameSetRetimingData( Abc_Frame_t * pAbc, int * pRst, int * pSet, int * pEna, int nRegs ) { Gia_Man_t * pGia; + int * pRstNew = ABC_CALLOC( int, nRegs ); + int * pSetNew = ABC_CALLOC( int, nRegs ); + int * pEnaNew = ABC_CALLOC( int, nRegs ); if ( pAbc == NULL ) printf( "ABC framework is not initialized by calling Abc_Start()\n" ); pGia = Abc_FrameReadGia( pAbc ); if ( pGia == NULL ) printf( "Current network in ABC framework is not defined.\n" ); + else { + assert( nRegs == Gia_ManRegNum(pGia) ); + memmove( pRstNew, pRst, sizeof(int)*nRegs ); + memmove( pSetNew, pSet, sizeof(int)*nRegs ); + memmove( pEnaNew, pEna, sizeof(int)*nRegs ); + } + if ( pAbc->vCopyMiniAig == NULL ) + printf( "Mapping of MiniAig nodes is not available.\n" ); + else { + Abc_FrameRemapLits( pRstNew, nRegs, pAbc->vCopyMiniAig ); + Abc_FrameRemapLits( pSetNew, nRegs, pAbc->vCopyMiniAig ); + Abc_FrameRemapLits( pEnaNew, nRegs, pAbc->vCopyMiniAig ); + } assert( pGia->vStopsF == NULL ); assert( pGia->vStopsB == NULL ); - pGia->vStopsF = Gia_ManRetimableF( pGia, pRst, pSet, pEna ); - pGia->vStopsB = Gia_ManRetimableB( pGia, pRst, pSet, pEna ); + pGia->vStopsF = Gia_ManRetimableF( pGia, pRstNew, pSetNew, pEnaNew ); + pGia->vStopsB = Gia_ManRetimableB( pGia, pRstNew, pSetNew, pEnaNew ); + ABC_FREE( pRstNew ); + ABC_FREE( pSetNew ); + ABC_FREE( pEnaNew ); } //////////////////////////////////////////////////////////////////////// diff --git a/src/base/main/abcapis.h b/src/base/main/abcapis.h index e1e05f4c7d..30494f77c5 100644 --- a/src/base/main/abcapis.h +++ b/src/base/main/abcapis.h @@ -107,7 +107,7 @@ extern ABC_DLL int Abc_FrameReadProbStatus( Abc_Frame_t * pAbc ); extern ABC_DLL void * Abc_FrameReadCex( Abc_Frame_t * pAbc ); // procedure to set retiming data -extern ABC_DLL void Abc_FrameSetRetimingData( Abc_Frame_t * pAbc, int * pRst, int * pSet, int * pEna ); +extern ABC_DLL void Abc_FrameSetRetimingData( Abc_Frame_t * pAbc, int * pRst, int * pSet, int * pEna, int nRegs ); // procedure to return sequential equivalences extern ABC_DLL int * Abc_FrameReadMiniAigEquivClasses( Abc_Frame_t * pAbc ); From 3c4c558656a35c6947569eb703412380b0f5b22d Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 2 Oct 2023 16:47:37 -0700 Subject: [PATCH 21/67] Experiment with script generation. --- src/base/cmd/cmd.c | 75 +++++++++++++++++++++++++++++++++++++++++ src/base/cmd/cmdUtils.c | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index 630355fa5a..80ba526123 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -59,6 +59,7 @@ static int CmdCommandScrGen ( Abc_Frame_t * pAbc, int argc, char ** argv static int CmdCommandScrGenLinux ( Abc_Frame_t * pAbc, int argc, char ** argv ); #endif static int CmdCommandVersion ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int CmdCommandSGen ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandSis ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandMvsis ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandCapo ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -111,6 +112,7 @@ void Cmd_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Basic", "scrgen", CmdCommandScrGenLinux, 0 ); #endif Cmd_CommandAdd( pAbc, "Basic", "version", CmdCommandVersion, 0 ); + Cmd_CommandAdd( pAbc, "Basic", "sgen", CmdCommandSGen, 0 ); Cmd_CommandAdd( pAbc, "Various", "sis", CmdCommandSis, 1 ); Cmd_CommandAdd( pAbc, "Various", "mvsis", CmdCommandMvsis, 1 ); @@ -2761,6 +2763,79 @@ int CmdCommandVersion( Abc_Frame_t * pAbc, int argc, char **argv ) return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int CmdCommandSGen( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Cmd_CommandSGen( Abc_Frame_t * pAbc, int nParts, int nIters, int fVerbose ); + int c, nParts = 10; + int nIters = 10; + int fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "NIvh" ) ) != EOF ) + { + switch ( c ) + { + case 'N': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-N\" should be followed by an integer.\n" ); + goto usage; + } + nParts = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nParts < 0 ) + goto usage; + break; + case 'I': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-I\" should be followed by a string (possibly in quotes).\n" ); + goto usage; + } + nIters = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( Abc_FrameReadNtk(pAbc) == NULL ) + { + Abc_Print( -2, "There is no current network.\n" ); + return 1; + } + if ( !Abc_NtkIsStrash(Abc_FrameReadNtk(pAbc)) ) + { + Abc_Print( -2, "The current network is not an AIG.\n" ); + return 1; + } + Cmd_CommandSGen( pAbc, nParts, nIters, fVerbose ); + return 0; + +usage: + Abc_Print( -2, "usage: sgen [-N num] [-I num] [-vh]\n" ); + Abc_Print( -2, "\t experiment with script generation\n" ); + Abc_Print( -2, "\t-N num : the number of commands to use [default = %d]\n", nParts ); + Abc_Print( -2, "\t-I num : the number of iterations to perform [default = %d]\n", nIters ); + Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} //////////////////////////////////////////////////////////////////////// /// END OF FILE /// diff --git a/src/base/cmd/cmdUtils.c b/src/base/cmd/cmdUtils.c index 2158f8e977..a5dc6972b4 100644 --- a/src/base/cmd/cmdUtils.c +++ b/src/base/cmd/cmdUtils.c @@ -833,6 +833,70 @@ void Gia_ManKissatCall( Abc_Frame_t * pAbc, char * pFileName, char * pArgs, int } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Cmd_GenScript( char ** pComms, int nComms, int nParts ) +{ + static char pScript[1000]; int c; + pScript[0] = 0; + for ( c = 0; c < nParts; c++ ) { + strcat( pScript, pComms[rand() % nComms] ); + strcat( pScript, "; " ); + } + strcat( pScript, "print_stats" ); + return pScript; +} +void Cmd_CommandSGen( Abc_Frame_t * pAbc, int nParts, int nIters, int fVerbose ) +{ + Abc_Ntk_t * pCopy = Abc_NtkDup( Abc_FrameReadNtk(pAbc) ); + Abc_Ntk_t * pBest = Abc_NtkDup( Abc_FrameReadNtk(pAbc) ); + Abc_Ntk_t * pCur = NULL; int i; + char * pComms[6] = { "balance", "rewrite", "rewrite -z", "refactor", "refactor -z", "resub" }; + srand( time(NULL) ); + for ( i = 0; i < nIters; i++ ) + { + char * pScript = Cmd_GenScript( pComms, 6, nParts ); + Abc_FrameSetCurrentNetwork( pAbc, Abc_NtkDup(pCopy) ); + if ( Abc_FrameIsBatchMode() ) + { + if ( Cmd_CommandExecute(pAbc, pScript) ) + { + Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pScript ); + return; + } + } + else + { + Abc_FrameSetBatchMode( 1 ); + if ( Cmd_CommandExecute(pAbc, pScript) ) + { + Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pScript ); + Abc_FrameSetBatchMode( 0 ); + return; + } + Abc_FrameSetBatchMode( 0 ); + } + pCur = Abc_FrameReadNtk(pAbc); + if ( Abc_NtkNodeNum(pCur) < Abc_NtkNodeNum(pBest) ) { + Abc_Obj_t * pObj; int k; + Abc_NtkForEachObj( pBest, pObj, k ) + pObj->fMarkA = pObj->fMarkB = pObj->fMarkC = 0; + Abc_NtkDelete( pBest ); + pBest = Abc_NtkDup( pCur ); + } + } + Abc_FrameSetCurrentNetwork( pAbc, pBest ); + Abc_NtkDelete( pCopy ); +} //////////////////////////////////////////////////////////////////////// /// END OF FILE /// From 72b423ba14e416463a06c66c7c908250f4458f45 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 20 Oct 2023 20:53:43 -0700 Subject: [PATCH 22/67] Experiments with SAT solving. --- src/aig/gia/giaUtil.c | 113 ++++++++++++++++++++++++++++++++++++++++++ src/base/abci/abc.c | 91 +++++++++++++++++++++++++++++++++- src/base/io/io.c | 71 ++++++++++++++++++++++++++ src/base/io/ioUtil.c | 87 ++++++++++++++++++++++++++++++++ 4 files changed, 361 insertions(+), 1 deletion(-) diff --git a/src/aig/gia/giaUtil.c b/src/aig/gia/giaUtil.c index dfddc69318..69a6e7235c 100644 --- a/src/aig/gia/giaUtil.c +++ b/src/aig/gia/giaUtil.c @@ -3161,6 +3161,119 @@ void Gia_ManPrintArray( Gia_Man_t * p ) printf( "};\n" ); } + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Gia_GetMValue( int i, int nIns, int Mint, unsigned Truth ) +{ + assert( i >= 0 && i < 16 ); + if ( i < nIns ) + return (Mint >> i) & 1; + if ( i == nIns ) + { + if ( Mint < (1 << nIns) ) + return (Truth >> Mint) & 1; + else + return ((Truth >> (Mint-(1 << nIns))) & 1) == 0; + } + else + return 1; +} +void Gia_ManTestProblem() +{ + unsigned Truth = 0xFE; + int i, j, k, c, nIns = 3, nAux = 3; + int nTotal = nIns + 1 + nAux; + int nPairs = nTotal * (nTotal - 1) / 2; + int nMints = (1 << (nIns+1)); + int M[64][100] = {{0}}; + float Value[64] = {0}; + float Solution[100] = {0}; + assert( nMints <= 64 ); + assert( nPairs <= 100 ); + // 7 nodes: 3 inputs + 1 output + 3 aux + // 7*6/2 = 21 pairs + // 16 minterms + for ( k = 0; k < nMints; k++ ) + { + for ( i = c = 0; i < nTotal; i++ ) + for ( j = i+1; j < nTotal; j++ ) + { + int iVal = Gia_GetMValue( i, nIns, k, Truth ); + int jVal = Gia_GetMValue( j, nIns, k, Truth ); + M[k][c++] = iVal == jVal ? 1 : -1; + } + Value[k] = k < (1 << nIns) ? -1 : 1; + assert( c == nPairs ); + } + + for ( k = 0; k < nMints; k++ ) + { + for ( c = 0; c < nPairs; c++ ) + printf( "%2d ", M[k][c] ); + printf( "%3f\n", Value[k] ); + } + + // solve + float Delta = 0.02; + for ( i = 0; i < 100; i++ ) + { + float Error = 0; + for ( k = 0; k < nMints; k++ ) + Error += Value[k] > 0 ? Value[k] : -Value[k]; + printf( "Round %3d : Error = %5f ", i, Error ); + for ( c = 0; c < nPairs; c++ ) + printf( "%2f ", Solution[c] ); + printf( "\n" ); + + //if ( Error < 1 ) + // Delta /= 10; + + for ( c = 0; c < nPairs; c++ ) + { + int Count = 0; + for ( k = 0; k < nMints; k++ ) + if ( (M[k][c] > 0 && Value[k] > 0) || (M[k][c] < 0 && Value[k] < 0) ) + Count++; + else + Count--; + if ( Count == 0 ) + continue; + printf( "Count = %3d ", Count ); + if ( Count > 0 ) + { + printf( "Increasing %d by %f\n", c, Delta ); + Solution[c] += Delta; + for ( k = 0; k < nMints; k++ ) + if ( M[k][c] > 0 ) + Value[k] -= Delta; + else + Value[k] -= Delta; + } + else + { + printf( "Reducing %d by %f\n", c, Delta ); + Solution[c] -= Delta; + for ( k = 0; k < nMints; k++ ) + if ( M[k][c] > 0 ) + Value[k] += Delta; + else + Value[k] += Delta; + } + } + } +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 586ac2c57e..43207c8878 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -139,6 +139,7 @@ static int Abc_CommandTestDec ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandTestNpn ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandTestRPO ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandTestTruth ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandRunSat ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandRunEco ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandRunGen ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandRunTest ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -914,6 +915,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Synthesis", "testnpn", Abc_CommandTestNpn, 0 ); Cmd_CommandAdd( pAbc, "LogiCS", "testrpo", Abc_CommandTestRPO, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "testtruth", Abc_CommandTestTruth, 0 ); + Cmd_CommandAdd( pAbc, "Synthesis", "runsat", Abc_CommandRunSat, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "runeco", Abc_CommandRunEco, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "rungen", Abc_CommandRunGen, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "xec", Abc_CommandRunTest, 0 ); @@ -7168,6 +7170,93 @@ int Abc_CommandTestTruth( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandRunSat( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + FILE * pFile = NULL; + char * pFileCnf = NULL; + int c, i, fWalk = 0, fKissat = 0, nIters = 10, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "Ikwvh" ) ) != EOF ) + { + switch ( c ) + { + case 'I': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-I\" should be followed by an integer.\n" ); + goto usage; + } + nIters = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nIters < 0 ) + goto usage; + break; + case 'k': + fKissat ^= 1; + break; + case 'w': + fWalk ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( fKissat + fWalk != 1 ) { + printf( "Exactly one SAT solver should be selected.\n" ); + return 1; + } + if ( argc != globalUtilOptind + 1 ) + goto usage; + pFileCnf = argv[globalUtilOptind]; + pFile = fopen( pFileCnf, "rb" ); + if ( pFile == NULL ) { + printf( "The file \"%s\" cannot be found.\n", pFileCnf ); + return 1; + } + fclose( pFile ); + abctime clk = Abc_Clock(); + for ( i = 0; i < nIters; i++ ) { + char pCommand[1000]; + if ( fKissat ) + sprintf( pCommand, "kissat -q --seed=%d %s", i, pFileCnf ); + else if ( fWalk ) + sprintf( pCommand, "walk -s%d %s", i, pFileCnf ); + if (system(pCommand) == -1) { + fprintf(stdout, "Command \"%s\" did not succeed.\n", pCommand); + return 0; + } + } + printf( "Performed %d iterations of SAT solving. ", nIters ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + return 0; + +usage: + Abc_Print( -2, "usage: runsat [-I num] [-kwvh] \n" ); + Abc_Print( -2, "\t performs randomized iterations of SAT solving\n" ); + Abc_Print( -2, "\t-I num : the number of iterations [default = %d]\n", nIters ); + Abc_Print( -2, "\t-k : toggle using Kissat (binary name \"kissat\") [default = %s]\n", fKissat? "yes": "no" ); + Abc_Print( -2, "\t-w : toggle using WalkSat (binary name \"walk\") [default = %s]\n", fWalk? "yes": "no" ); + Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] @@ -14622,7 +14711,7 @@ int Abc_CommandTest( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes ); } */ - + //Gia_ManTestProblem(); return 0; usage: Abc_Print( -2, "usage: test [-CKDNM] [-aovwh] \n" ); diff --git a/src/base/io/io.c b/src/base/io/io.c index e808d1d0b0..f988a00785 100644 --- a/src/base/io/io.c +++ b/src/base/io/io.c @@ -52,6 +52,7 @@ static int IoCommandReadInit ( Abc_Frame_t * pAbc, int argc, char **argv ); static int IoCommandReadPla ( Abc_Frame_t * pAbc, int argc, char **argv ); static int IoCommandReadPlaMo ( Abc_Frame_t * pAbc, int argc, char **argv ); static int IoCommandReadTruth ( Abc_Frame_t * pAbc, int argc, char **argv ); +static int IoCommandReadCnf ( Abc_Frame_t * pAbc, int argc, char **argv ); static int IoCommandReadVerilog ( Abc_Frame_t * pAbc, int argc, char **argv ); static int IoCommandReadStatus ( Abc_Frame_t * pAbc, int argc, char **argv ); static int IoCommandReadGig ( Abc_Frame_t * pAbc, int argc, char **argv ); @@ -124,6 +125,7 @@ void Io_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "I/O", "read_pla", IoCommandReadPla, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_plamo", IoCommandReadPlaMo, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_truth", IoCommandReadTruth, 1 ); + Cmd_CommandAdd( pAbc, "I/O", "read_cnf", IoCommandReadCnf, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_verilog", IoCommandReadVerilog, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_status", IoCommandReadStatus, 0 ); Cmd_CommandAdd( pAbc, "I/O", "&read_gig", IoCommandReadGig, 0 ); @@ -1209,6 +1211,75 @@ int IoCommandReadTruth( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int IoCommandReadCnf( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Vec_Ptr_t * Io_FileReadCnf( char * pFileName ); + FILE * pFile; + Abc_Ntk_t * pNtk; + Vec_Ptr_t * vSops; + int c; + + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF ) + { + switch ( c ) + { + case 'h': + goto usage; + default: + goto usage; + } + } + + if ( argc != globalUtilOptind + 1 ) + goto usage; + + pFile = fopen( argv[globalUtilOptind], "rb" ); + if ( pFile == NULL ) + { + printf( "The file \"%s\" cannot be found.\n", argv[globalUtilOptind] ); + return 1; + } + else + fclose( pFile ); + vSops = Io_FileReadCnf( argv[globalUtilOptind] ); + if ( Vec_PtrSize(vSops) == 0 ) + { + Vec_PtrFreeFree( vSops ); + fprintf( pAbc->Err, "Reading CNF file has failed.\n" ); + return 1; + } + pNtk = Abc_NtkCreateWithNodes( vSops ); + Vec_PtrFreeFree( vSops ); + if ( pNtk == NULL ) + { + fprintf( pAbc->Err, "Deriving the network has failed.\n" ); + return 1; + } + // replace the current network + Abc_FrameReplaceCurrentNetwork( pAbc, pNtk ); + Abc_FrameClearVerifStatus( pAbc ); + return 0; + +usage: + fprintf( pAbc->Err, "usage: read_cnf [-h] \n" ); + fprintf( pAbc->Err, "\t creates network with one node\n" ); + fprintf( pAbc->Err, "\t-h : prints the command summary\n" ); + fprintf( pAbc->Err, "\tfile : file name with the truth table\n" ); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/base/io/ioUtil.c b/src/base/io/ioUtil.c index eef80efa33..e57fa9574d 100644 --- a/src/base/io/ioUtil.c +++ b/src/base/io/ioUtil.c @@ -920,6 +920,93 @@ void Io_TransformSF2PLA( char * pNameIn, char * pNameOut ) ABC_FREE( pBuffer ); } +/**Function************************************************************* + + Synopsis [Reads CNF from file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Io_ConvertNumsToSop( Vec_Wec_t * vNums, int nVars ) +{ + Vec_Int_t * vLevel; int i, k, Num; + int nSize = (nVars + 3)*Vec_WecSize(vNums); + char * pStr = ABC_ALLOC( char, nSize+1 ); + memset( pStr, '-', nSize ); + pStr[nSize] = 0; + Vec_WecForEachLevel( vNums, vLevel, i ) + { + char * pCube = pStr + (nVars + 3)*i; + Vec_IntForEachEntry( vLevel, Num, k ) + pCube[Abc_Lit2Var(Num)] = '0' + Abc_LitIsCompl(Num); + pCube[nVars+0] = ' '; + pCube[nVars+1] = '1'; + pCube[nVars+2] = '\n'; + } + return pStr; +} +Vec_Ptr_t * Io_FileReadCnf( char * pFileName ) +{ + Vec_Ptr_t * vSops = Vec_PtrAlloc( 1 ); + Vec_Wec_t * vNums = Vec_WecAlloc( 100 ); + Vec_Int_t * vLevel; + char * pThis, pLine[10000]; + int nVars = -1, nClas = -1; + FILE * pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) { + printf( "Cannot open file \"%s\" for reading.\n", pFileName ); + return NULL; + } + while ( fgets( pLine, 10000, pFile ) ) + { + if ( pLine[0] == 'c' ) + continue; + if ( pLine[0] == 'p' ) + { + pThis = strtok(pLine+1, " \t\n\r"); + if ( strcmp(pThis, "cnf") ) + { + Vec_PtrFree( vSops ); + Vec_WecFree( vNums ); + fclose( pFile ); + printf( "Wrong file format.\n" ); + return NULL; + } + pThis = strtok(NULL, " \t\n\r"); + nVars = atoi(pThis); + pThis = strtok(NULL, " \t\n\r"); + nClas = atoi(pThis); + continue; + } + pThis = strtok(pLine, " \t\n\r"); + if ( pThis == NULL ) + continue; + vLevel = Vec_WecPushLevel( vNums ); + while ( pThis ) { + int fComp, Temp = atoi(pThis); + if ( Temp == 0 ) + break; + fComp = Temp < 0; + Temp = Temp < 0 ? -Temp : Temp; + Temp -= 1; + assert( Temp < nVars ); + Vec_IntPush( vLevel, Abc_Var2Lit(Temp, fComp) ); + pThis = strtok(NULL, " \t\n\r"); + } + } + fclose( pFile ); + if ( nClas != Vec_WecSize(vNums) ) + printf( "Warning: The number of clauses (%d) listed is different from the actual number (%d).\n", nClas, Vec_WecSize(vNums) ); + //Vec_WecPrint( vNums, 0 ); + Vec_PtrPush( vSops, Io_ConvertNumsToSop(vNums, nVars) ); + Vec_WecFree( vNums ); + return vSops; +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// From 652a0aaef7804280eb2a9721d7e85dda946543ac Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 20 Oct 2023 22:42:40 -0700 Subject: [PATCH 23/67] Compiler warning. --- src/base/abci/abc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 43207c8878..f93d03ff0e 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -7186,6 +7186,7 @@ int Abc_CommandRunSat( Abc_Frame_t * pAbc, int argc, char ** argv ) FILE * pFile = NULL; char * pFileCnf = NULL; int c, i, fWalk = 0, fKissat = 0, nIters = 10, fVerbose = 0; + abctime clk; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "Ikwvh" ) ) != EOF ) { @@ -7230,7 +7231,7 @@ int Abc_CommandRunSat( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } fclose( pFile ); - abctime clk = Abc_Clock(); + clk = Abc_Clock(); for ( i = 0; i < nIters; i++ ) { char pCommand[1000]; if ( fKissat ) From 8dbf8965fdbbabc1101412272b2ef0ff9140b578 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Oct 2023 09:37:04 -0700 Subject: [PATCH 24/67] Adding batch option to "scrgen". --- src/base/cmd/cmd.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index 80ba526123..d8ba90f587 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -1867,10 +1867,11 @@ int CmdCommandScrGenLinux( Abc_Frame_t * pAbc, int argc, char **argv ) char * pWriteExt = NULL; char Line[2000], * pName; int nFileNameMax; + int fBatch = 0; int c, k; Extra_UtilGetoptReset(); - while ( (c = Extra_UtilGetopt(argc, argv, "FRCWEh") ) != EOF ) + while ( (c = Extra_UtilGetopt(argc, argv, "FRCWEbh") ) != EOF ) { switch (c) { @@ -1919,6 +1920,9 @@ int CmdCommandScrGenLinux( Abc_Frame_t * pAbc, int argc, char **argv ) pWriteExt = argv[globalUtilOptind]; globalUtilOptind++; break; + case 'b': + fBatch ^= 1; + break; default: goto usage; } @@ -1952,7 +1956,7 @@ int CmdCommandScrGenLinux( Abc_Frame_t * pAbc, int argc, char **argv ) char * pExt = strstr(pName, "."); if ( !pExt || !strcmp(pExt, ".") || !strcmp(pExt, "..") || !strcmp(pExt, ".s") || !strcmp(pExt, ".txt") ) continue; - sprintf( Line, "%sread %s%s%-*s ; %s", fAndSpace ? "&" : "", pDirStr?pDirStr:"", pDirStr?"/":"", nFileNameMax, pName, pComStr ); + sprintf( Line, "%s%sread %s%s%-*s ; %s", fBatch ? "./abc -c \"":"", fAndSpace ? "&" : "", pDirStr?pDirStr:"", pDirStr?"/":"", nFileNameMax, pName, pComStr ); for ( c = (int)strlen(Line)-1; c >= 0; c-- ) if ( Line[c] == '\\' ) Line[c] = '/'; @@ -1966,6 +1970,8 @@ int CmdCommandScrGenLinux( Abc_Frame_t * pAbc, int argc, char **argv ) Line[c] = '/'; fprintf( pFile, "%s", Line ); } + if ( fBatch ) + fprintf( pFile, "\"" ); fprintf( pFile, "\n" ); } } @@ -1975,13 +1981,14 @@ int CmdCommandScrGenLinux( Abc_Frame_t * pAbc, int argc, char **argv ) return 0; usage: - fprintf( pAbc->Err, "usage: scrgen -F -R -C -W -E -h\n" ); + fprintf( pAbc->Err, "usage: scrgen -F -R -C -W -E -bh\n" ); fprintf( pAbc->Err, "\t generates script for running ABC\n" ); fprintf( pAbc->Err, "\t-F str : the name of the script file [default = \"test.s\"]\n" ); fprintf( pAbc->Err, "\t-R str : the directory to read files from [default = current]\n" ); fprintf( pAbc->Err, "\t-C str : the sequence of commands to run [default = \"ps\"]\n" ); fprintf( pAbc->Err, "\t-W str : the directory to write the resulting files [default = no writing]\n" ); fprintf( pAbc->Err, "\t-E str : the output files extension (with \".\") [default = the same as input files]\n" ); + fprintf( pAbc->Err, "\t-b : toggles adding batch mode support [default = %s]\n", fBatch? "yes": "no" ); fprintf( pAbc->Err, "\t-h : print the command usage\n\n"); fprintf( pAbc->Err, "\tExample : scrgen -F test1.s -R a/in -C \"ps; st; ps\" -W a/out -E .blif\n" ); return 1; From 01ad71b26f983b61ea0faae7eacb2cc60a285793 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Oct 2023 09:38:08 -0700 Subject: [PATCH 25/67] Experiments with verification. --- src/base/abci/abc.c | 34 +++++- src/base/io/ioUtil.c | 2 +- src/proof/cec/cecProve.c | 216 +++++++++++++++++++++++++++++++-------- 3 files changed, 204 insertions(+), 48 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index f93d03ff0e..0558eefa4d 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -46383,10 +46383,10 @@ int Abc_CommandAbc9SplitProve( Abc_Frame_t * pAbc, int argc, char ** argv ) ***********************************************************************/ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int fVerbose, int fVeryVerbose, int fSilent ); - int c, nProcs = 5, nTimeOut = 3, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; + extern int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fVerbose, int fVeryVerbose, int fSilent ); + int c, nProcs = 5, nTimeOut = 3, nTimeOut2 = 10, nTimeOut3 = 100, fVerbose = 0, fVeryVerbose = 0, fSilent = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "PTsvwh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "PTUWsvwh" ) ) != EOF ) { switch ( c ) { @@ -46412,6 +46412,28 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( nTimeOut <= 0 ) goto usage; break; + case 'U': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-U\" should be followed by a positive integer.\n" ); + goto usage; + } + nTimeOut2 = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nTimeOut2 <= 0 ) + goto usage; + break; + case 'W': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-W\" should be followed by a positive integer.\n" ); + goto usage; + } + nTimeOut3 = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nTimeOut3 <= 0 ) + goto usage; + break; case 's': fSilent ^= 1; break; @@ -46437,15 +46459,17 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Abc_CommandAbc9SProve(): The problem is combinational.\n" ); return 1; } - pAbc->Status = Cec_GiaProveTest( pAbc->pGia, nProcs, nTimeOut, fVerbose, fVeryVerbose, fSilent ); + pAbc->Status = Cec_GiaProveTest( pAbc->pGia, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fVerbose, fVeryVerbose, fSilent ); Abc_FrameReplaceCex( pAbc, &pAbc->pGia->pCexSeq ); return 0; usage: - Abc_Print( -2, "usage: &sprove [-PT num] [-svwh]\n" ); + Abc_Print( -2, "usage: &sprove [-PTUW num] [-svwh]\n" ); Abc_Print( -2, "\t proves CEC problem by case-splitting\n" ); Abc_Print( -2, "\t-P num : the number of concurrent processes [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-W num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut3 ); Abc_Print( -2, "\t-s : enable silent computation (no reporting) [default = %s]\n", fSilent? "yes": "no" ); 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" ); diff --git a/src/base/io/ioUtil.c b/src/base/io/ioUtil.c index e57fa9574d..d11ee74080 100644 --- a/src/base/io/ioUtil.c +++ b/src/base/io/ioUtil.c @@ -944,7 +944,7 @@ char * Io_ConvertNumsToSop( Vec_Wec_t * vNums, int nVars ) Vec_IntForEachEntry( vLevel, Num, k ) pCube[Abc_Lit2Var(Num)] = '0' + Abc_LitIsCompl(Num); pCube[nVars+0] = ' '; - pCube[nVars+1] = '1'; + pCube[nVars+1] = '0'; pCube[nVars+2] = '\n'; } return pStr; diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index 748f506f91..b3ddcd8a18 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -22,6 +22,11 @@ #include "aig/gia/gia.h" #include "aig/gia/giaAig.h" +#include "sat/bmc/bmc.h" +#include "proof/pdr/pdr.h" +#include "proof/cec/cec.h" +#include "proof/ssw/ssw.h" + #ifdef ABC_USE_PTHREADS @@ -41,9 +46,12 @@ ABC_NAMESPACE_IMPL_START /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// +extern int Ssw_RarSimulateGia( Gia_Man_t * p, Ssw_RarPars_t * pPars ); +extern int Bmcg_ManPerform( Gia_Man_t * pGia, Bmc_AndPar_t * pPars ); + #ifndef ABC_USE_PTHREADS -int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int fVerbose, int fVeryVerbose, int fSilent ) { return -1; } +int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fVerbose, int fVeryVerbose, int fSilent ) { return -1; } #else // pthreads are used @@ -62,28 +70,106 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int fVerbose, int SeeAlso [] ***********************************************************************/ -int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, Abc_Cex_t ** ppCex ) +int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose ) { - abctime clk = Abc_Clock(); + abctime clk = Abc_Clock(); + int RetValue = -1; //abctime clkStop = nTimeOut * CLOCKS_PER_SEC + Abc_Clock(); + if ( fVerbose ) printf( "Calling engine %d with timeout %d sec.\n", iEngine, nTimeOut ); + Abc_CexFreeP( &p->pCexSeq ); if ( iEngine == 0 ) { + Ssw_RarPars_t Pars, * pPars = &Pars; + Ssw_RarSetDefaultParams( pPars ); + pPars->TimeOut = nTimeOut; + pPars->fSilent = 1; + RetValue = Ssw_RarSimulateGia( p, pPars ); } else if ( iEngine == 1 ) { - } + Saig_ParBmc_t Pars, * pPars = &Pars; + Saig_ParBmcSetDefaultParams( pPars ); + pPars->nTimeOut = nTimeOut; + pPars->fSilent = 1; + Aig_Man_t * pAig = Gia_ManToAigSimple( p ); + RetValue = Saig_ManBmcScalable( pAig, pPars ); + p->pCexSeq = pAig->pSeqModel; pAig->pSeqModel = NULL; + Aig_ManStop( pAig ); + } else if ( iEngine == 2 ) { - } + Pdr_Par_t Pars, * pPars = &Pars; + Pdr_ManSetDefaultParams( pPars ); + pPars->nTimeOut = nTimeOut; + pPars->fSilent = 1; + Aig_Man_t * pAig = Gia_ManToAigSimple( p ); + RetValue = Pdr_ManSolve( pAig, pPars ); + p->pCexSeq = pAig->pSeqModel; pAig->pSeqModel = NULL; + Aig_ManStop( pAig ); + } else if ( iEngine == 3 ) { + Saig_ParBmc_t Pars, * pPars = &Pars; + Saig_ParBmcSetDefaultParams( pPars ); + pPars->fUseGlucose = 1; + pPars->nTimeOut = nTimeOut; + pPars->fSilent = 1; + Aig_Man_t * pAig = Gia_ManToAigSimple( p ); + RetValue = Saig_ManBmcScalable( pAig, pPars ); + p->pCexSeq = pAig->pSeqModel; pAig->pSeqModel = NULL; + Aig_ManStop( pAig ); + } + else if ( iEngine == 4 ) + { + Pdr_Par_t Pars, * pPars = &Pars; + Pdr_ManSetDefaultParams( pPars ); + pPars->fUseAbs = 1; + pPars->nTimeOut = nTimeOut; + pPars->fSilent = 1; + Aig_Man_t * pAig = Gia_ManToAigSimple( p ); + RetValue = Pdr_ManSolve( pAig, pPars ); + p->pCexSeq = pAig->pSeqModel; pAig->pSeqModel = NULL; + Aig_ManStop( pAig ); + } + else if ( iEngine == 5 ) + { + Bmc_AndPar_t Pars, * pPars = &Pars; + memset( pPars, 0, sizeof(Bmc_AndPar_t) ); + pPars->nProcs = 1; // the number of parallel solvers + pPars->nFramesAdd = 1; // the number of additional frames + pPars->fNotVerbose = 1; // silent + pPars->nTimeOut = nTimeOut; // timeout in seconds + RetValue = Bmcg_ManPerform( p, pPars ); } else assert( 0 ); //while ( Abc_Clock() < clkStop ); - printf( "Engine %d finished. ", iEngine ); - Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); - return 0; + if ( fVerbose ) { + printf( "Engine %d finished and %ssolved the problem. ", iEngine, RetValue != -1 ? " " : "not " ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + } + return RetValue; +} +Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p ) +{ + Ssw_Pars_t Pars, * pPars = &Pars; + Ssw_ManSetDefaultParams( pPars ); + Aig_Man_t * pAig = Gia_ManToAigSimple( p ); + Aig_Man_t * pAig2 = Ssw_SignalCorrespondence( pAig, pPars ); + Gia_Man_t * pGia2 = Gia_ManFromAigSimple( pAig2 ); + Aig_ManStop( pAig2 ); + Aig_ManStop( pAig ); + return pGia2; +} +Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p ) +{ + Cec_ParCor_t Pars, * pPars = &Pars; + Cec_ManCorSetDefaultParams( pPars ); + pPars->nBTLimit = 100; + pPars->nLevelMax = 100; + pPars->fVerbose = 0; + pPars->fUseCSat = 1; + return Cec_ManLSCorrespondence( p, pPars ); } /**Function************************************************************* @@ -101,11 +187,11 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, Abc_Cex_t ** ppCe typedef struct Par_ThData_t_ { Gia_Man_t * p; - Abc_Cex_t * pCex; int iEngine; int fWorking; int nTimeOut; int Result; + int fVerbose; } Par_ThData_t; void * Cec_GiaProveWorkerThread( void * pArg ) { @@ -121,73 +207,119 @@ void * Cec_GiaProveWorkerThread( void * pArg ) assert( 0 ); return NULL; } - pThData->Result = Cec_GiaProveOne( pThData->p, pThData->iEngine, pThData->nTimeOut, &pThData->pCex ); + pThData->Result = Cec_GiaProveOne( pThData->p, pThData->iEngine, pThData->nTimeOut, pThData->fVerbose ); pThData->fWorking = 0; } assert( 0 ); return NULL; } -int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int fVerbose, int fVeryVerbose, int fSilent ) +void Cec_GiaInitThreads( Par_ThData_t * ThData, int nProcs, Gia_Man_t * p, int nTimeOut, int fVerbose, pthread_t * WorkerThread ) { - abctime clkTotal = Abc_Clock(); - Par_ThData_t ThData[PAR_THR_MAX]; - pthread_t WorkerThread[PAR_THR_MAX]; - int i, status, RetValue = -1; - Abc_CexFreeP( &p->pCexComb ); - Abc_CexFreeP( &p->pCexSeq ); - if ( fVerbose ) - printf( "Solving verification problem with the following parameters:\n" ); - if ( fVerbose ) - printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", nProcs, nTimeOut, fVerbose ); - fflush( stdout ); - if ( nProcs == 1 ) - return -1; - // subtract manager thread - nProcs--; - assert( (nProcs == 4 || nProcs == 8) && nProcs <= PAR_THR_MAX ); - // start threads + int i, status; + assert( nProcs <= PAR_THR_MAX ); for ( i = 0; i < nProcs; i++ ) { ThData[i].p = Gia_ManDup(p); - ThData[i].pCex = NULL; ThData[i].iEngine = i; ThData[i].nTimeOut = nTimeOut; ThData[i].fWorking = 0; ThData[i].Result = -1; + ThData[i].fVerbose = fVerbose; + if ( !WorkerThread ) + continue; status = pthread_create( WorkerThread + i, NULL,Cec_GiaProveWorkerThread, (void *)(ThData + i) ); assert( status == 0 ); } - for ( i = 0; i < nProcs; i++ ) ThData[i].fWorking = 1; - - // wait till threads finish +} +int Cec_GiaWaitThreads( Par_ThData_t * ThData, int nProcs, Gia_Man_t * p, int RetValue, int * pRetEngine ) +{ + int i; for ( i = 0; i < nProcs; i++ ) + { + if ( RetValue == -1 && !ThData[i].fWorking && ThData[i].Result != -1 ) { + RetValue = ThData[i].Result; + *pRetEngine = i; + if ( !p->pCexSeq && ThData[i].p->pCexSeq ) + p->pCexSeq = Abc_CexDup( ThData[i].p->pCexSeq, -1 ); + } if ( ThData[i].fWorking ) i = -1; + } + return RetValue; +} + +int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fVerbose, int fVeryVerbose, int fSilent ) +{ + abctime clkScorr = 0, clkTotal = Abc_Clock(); + Par_ThData_t ThData[PAR_THR_MAX]; + pthread_t WorkerThread[PAR_THR_MAX]; + int i, RetValue = -1, RetEngine = -2; + Abc_CexFreeP( &p->pCexComb ); + Abc_CexFreeP( &p->pCexSeq ); + if ( !fSilent && fVerbose ) + printf( "Solving verification problem with the following parameters:\n" ); + if ( !fSilent && fVerbose ) + printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", nProcs, nTimeOut, fVerbose ); + fflush( stdout ); + + assert( nProcs == 3 || nProcs == 5 ); + Cec_GiaInitThreads( ThData, nProcs, p, nTimeOut, fVerbose, WorkerThread ); + + // meanwhile, perform scorr + Gia_Man_t * pScorr = Cec_GiaScorrNew( p ); + clkScorr = Abc_Clock() - clkTotal; + if ( Gia_ManAndNum(pScorr) == 0 ) + RetValue = 1, RetEngine = -1; + + RetValue = Cec_GiaWaitThreads( ThData, nProcs, p, RetValue, &RetEngine ); + if ( RetValue == -1 ) + { + abctime clkScorr2, clkStart = Abc_Clock(); + if ( !fSilent && fVerbose ) { + printf( "Reduced the miter from %d to %d nodes. ", Gia_ManAndNum(p), Gia_ManAndNum(pScorr) ); + Abc_PrintTime( 1, "Time", clkScorr ); + } + Cec_GiaInitThreads( ThData, nProcs, pScorr, nTimeOut2, fVerbose, NULL ); + + // meanwhile, perform scorr + Gia_Man_t * pScorr2 = Cec_GiaScorrOld( pScorr ); + clkScorr2 = Abc_Clock() - clkStart; + if ( Gia_ManAndNum(pScorr2) == 0 ) + RetValue = 1; + + RetValue = Cec_GiaWaitThreads( ThData, nProcs, p, RetValue, &RetEngine ); + if ( RetValue == -1 ) + { + if ( !fSilent && fVerbose ) { + printf( "Reduced the miter from %d to %d nodes. ", Gia_ManAndNum(pScorr), Gia_ManAndNum(pScorr2) ); + Abc_PrintTime( 1, "Time", clkScorr2 ); + } + Cec_GiaInitThreads( ThData, nProcs, pScorr2, nTimeOut3, fVerbose, NULL ); + + RetValue = Cec_GiaWaitThreads( ThData, nProcs, p, RetValue, &RetEngine ); + // do something else + } + Gia_ManStop( pScorr2 ); + } + Gia_ManStop( pScorr ); // stop threads for ( i = 0; i < nProcs; i++ ) { - assert( !ThData[i].fWorking ); - // cleanup - Gia_ManStopP( &ThData[i].p ); - if ( !p->pCexSeq && ThData[i].pCex ) - p->pCexSeq = Abc_CexDup( ThData[i].pCex, -1 ); - Abc_CexFreeP( &ThData[i].pCex ); - // stop ThData[i].p = NULL; ThData[i].fWorking = 1; } if ( !fSilent ) { if ( RetValue == 0 ) - printf( "Problem is SAT " ); + printf( "Problem is SAT (solved by %d) ", RetEngine ); else if ( RetValue == 1 ) - printf( "Problem is UNSAT " ); + printf( "Problem is UNSAT (solved by %d) ", RetEngine ); else if ( RetValue == -1 ) printf( "Problem is UNDECIDED " ); else assert( 0 ); - printf( ". " ); + printf( " " ); Abc_PrintTime( 1, "Time", Abc_Clock() - clkTotal ); fflush( stdout ); } From 538ecb4515a932816b3fa242b547c5cff599bb86 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Oct 2023 09:38:24 -0700 Subject: [PATCH 26/67] Updating printouts. --- src/proof/pdr/pdrCore.c | 4 ++-- src/sat/bmc/bmcBmcG.c | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/proof/pdr/pdrCore.c b/src/proof/pdr/pdrCore.c index d77fd4e17d..b98a4bbe37 100644 --- a/src/proof/pdr/pdrCore.c +++ b/src/proof/pdr/pdrCore.c @@ -1149,7 +1149,7 @@ int Pdr_ManSolveInt( Pdr_Man_t * p ) { if ( p->pPars->fVerbose ) Pdr_ManPrintProgress( p, 1, Abc_Clock() - clkStart ); - if ( p->timeToStop && Abc_Clock() > p->timeToStop ) + if ( p->timeToStop && Abc_Clock() > p->timeToStop && !p->pPars->fSilent ) Abc_Print( 1, "Reached timeout (%d seconds) in frame %d.\n", p->pPars->nTimeOut, iFrame ); else if ( p->pPars->nTimeOutGap && p->pPars->timeLastSolved && Abc_Clock() > p->pPars->timeLastSolved + p->pPars->nTimeOutGap * CLOCKS_PER_SEC ) Abc_Print( 1, "Reached gap timeout (%d seconds) in frame %d.\n", p->pPars->nTimeOutGap, iFrame ); @@ -1173,7 +1173,7 @@ int Pdr_ManSolveInt( Pdr_Man_t * p ) { if ( p->pPars->fVerbose ) Pdr_ManPrintProgress( p, 1, Abc_Clock() - clkStart ); - if ( p->timeToStop && Abc_Clock() > p->timeToStop ) + if ( p->timeToStop && Abc_Clock() > p->timeToStop && !p->pPars->fSilent ) Abc_Print( 1, "Reached timeout (%d seconds) in frame %d.\n", p->pPars->nTimeOut, iFrame ); else if ( p->pPars->nTimeOutGap && p->pPars->timeLastSolved && Abc_Clock() > p->pPars->timeLastSolved + p->pPars->nTimeOutGap * CLOCKS_PER_SEC ) Abc_Print( 1, "Reached gap timeout (%d seconds) in frame %d.\n", p->pPars->nTimeOutGap, iFrame ); diff --git a/src/sat/bmc/bmcBmcG.c b/src/sat/bmc/bmcBmcG.c index af141d303d..e6205b19c8 100644 --- a/src/sat/bmc/bmcBmcG.c +++ b/src/sat/bmc/bmcBmcG.c @@ -421,9 +421,11 @@ int Bmcg_ManPerformOne( Gia_Man_t * pGia, Bmc_AndPar_t * pPars ) break; } p->timeOth = Abc_Clock() - clkStart - p->timeUnf - p->timeCnf - p->timeSmp - p->timeSat; - if ( RetValue == -1 && !pPars->fNotVerbose ) - printf( "No output failed in %d frames. ", f + (k < pPars->nFramesAdd ? k+1 : 0) ); - Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart ); + if ( !pPars->fNotVerbose ) { + if ( RetValue == -1 && !pPars->fNotVerbose ) + printf( "No output failed in %d frames. ", f + (k < pPars->nFramesAdd ? k+1 : 0) ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart ); + } Bmcg_ManPrintTime( p ); Bmcg_ManStop( p ); return RetValue; From 76e8d21aafe3a5ae31d7516e33fbac5569384181 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Oct 2023 10:48:43 -0700 Subject: [PATCH 27/67] Printout changes. --- src/base/cmd/cmd.c | 14 +++++++------- src/base/cmd/cmdStarter.c | 10 ++++++---- src/proof/cec/cecProve.c | 40 +++++++++++++++++++++------------------ src/proof/ssw/sswRarity.c | 6 ++++-- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index d8ba90f587..708fc3f5b6 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -1956,7 +1956,7 @@ int CmdCommandScrGenLinux( Abc_Frame_t * pAbc, int argc, char **argv ) char * pExt = strstr(pName, "."); if ( !pExt || !strcmp(pExt, ".") || !strcmp(pExt, "..") || !strcmp(pExt, ".s") || !strcmp(pExt, ".txt") ) continue; - sprintf( Line, "%s%sread %s%s%-*s ; %s", fBatch ? "./abc -c \"":"", fAndSpace ? "&" : "", pDirStr?pDirStr:"", pDirStr?"/":"", nFileNameMax, pName, pComStr ); + sprintf( Line, "%s%sread %s%s%-*s ; %s", fBatch ? "./abc -q \"":"", fAndSpace ? "&" : "", pDirStr?pDirStr:"", pDirStr?"/":"", nFileNameMax, pName, pComStr ); for ( c = (int)strlen(Line)-1; c >= 0; c-- ) if ( Line[c] == '\\' ) Line[c] = '/'; @@ -2549,18 +2549,18 @@ int CmdCommandCapo( Abc_Frame_t * pAbc, int argc, char **argv ) ***********************************************************************/ int CmdCommandStarter( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores ); + extern void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores, int fVerbose ); FILE * pFile; char * pFileName; char * pCommand = NULL; int c, nCores = 3; int fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NCvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "PCvh" ) ) != EOF ) { switch ( c ) { - case 'N': + case 'P': if ( globalUtilOptind >= argc ) { Abc_Print( -1, "Command line switch \"-N\" should be followed by an integer.\n" ); @@ -2607,13 +2607,13 @@ int CmdCommandStarter( Abc_Frame_t * pAbc, int argc, char ** argv ) } fclose( pFile ); // run commands - Cmd_RunStarter( pFileName, pAbc->sBinary, pCommand, nCores ); + Cmd_RunStarter( pFileName, pAbc->sBinary, pCommand, nCores, fVerbose ); return 0; usage: - Abc_Print( -2, "usage: starter [-N num] [-C cmd] [-vh] \n" ); + Abc_Print( -2, "usage: starter [-P num] [-C cmd] [-vh] \n" ); Abc_Print( -2, "\t runs command lines listed in concurrently on CPUs\n" ); - Abc_Print( -2, "\t-N num : the number of concurrent jobs including the controller [default = %d]\n", nCores ); + Abc_Print( -2, "\t-P num : the number of concurrent jobs including the controller [default = %d]\n", nCores ); Abc_Print( -2, "\t-C cmd : (optional) ABC command line to execute on benchmarks in \n" ); Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); diff --git a/src/base/cmd/cmdStarter.c b/src/base/cmd/cmdStarter.c index ffb2b75220..bfbe5533d2 100644 --- a/src/base/cmd/cmdStarter.c +++ b/src/base/cmd/cmdStarter.c @@ -44,7 +44,7 @@ ABC_NAMESPACE_IMPL_START #ifndef ABC_USE_PTHREADS -void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores ) {} +void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores, int fVerbose ) {} #else // pthreads are used @@ -104,7 +104,7 @@ void * Abc_RunThread( void * pCommand ) SeeAlso [] ***********************************************************************/ -void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores ) +void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores, int fVerbose ) { FILE * pFile, * pFileTemp; pthread_t * pThreadIds; @@ -204,8 +204,10 @@ void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCor } else BufferCopy = Abc_UtilStrsav( Buffer ); - fprintf( stdout, "Calling: %s\n", (char *)BufferCopy ); - fflush( stdout ); + if ( fVerbose ) { + fprintf( stdout, "Calling: %s\n", (char *)BufferCopy ); + fflush( stdout ); + } // wait till there is an empty thread while ( 1 ) diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index b3ddcd8a18..b6325ea2c2 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -283,24 +283,27 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in Cec_GiaInitThreads( ThData, nProcs, pScorr, nTimeOut2, fVerbose, NULL ); // meanwhile, perform scorr - Gia_Man_t * pScorr2 = Cec_GiaScorrOld( pScorr ); - clkScorr2 = Abc_Clock() - clkStart; - if ( Gia_ManAndNum(pScorr2) == 0 ) - RetValue = 1; - - RetValue = Cec_GiaWaitThreads( ThData, nProcs, p, RetValue, &RetEngine ); - if ( RetValue == -1 ) + if ( Gia_ManAndNum(pScorr) < 100000 ) { - if ( !fSilent && fVerbose ) { - printf( "Reduced the miter from %d to %d nodes. ", Gia_ManAndNum(pScorr), Gia_ManAndNum(pScorr2) ); - Abc_PrintTime( 1, "Time", clkScorr2 ); + Gia_Man_t * pScorr2 = Cec_GiaScorrOld( pScorr ); + clkScorr2 = Abc_Clock() - clkStart; + if ( Gia_ManAndNum(pScorr2) == 0 ) + RetValue = 1; + + RetValue = Cec_GiaWaitThreads( ThData, nProcs, p, RetValue, &RetEngine ); + if ( RetValue == -1 ) + { + if ( !fSilent && fVerbose ) { + printf( "Reduced the miter from %d to %d nodes. ", Gia_ManAndNum(pScorr), Gia_ManAndNum(pScorr2) ); + Abc_PrintTime( 1, "Time", clkScorr2 ); + } + Cec_GiaInitThreads( ThData, nProcs, pScorr2, nTimeOut3, fVerbose, NULL ); + + RetValue = Cec_GiaWaitThreads( ThData, nProcs, p, RetValue, &RetEngine ); + // do something else } - Cec_GiaInitThreads( ThData, nProcs, pScorr2, nTimeOut3, fVerbose, NULL ); - - RetValue = Cec_GiaWaitThreads( ThData, nProcs, p, RetValue, &RetEngine ); - // do something else + Gia_ManStop( pScorr2 ); } - Gia_ManStop( pScorr2 ); } Gia_ManStop( pScorr ); @@ -312,12 +315,13 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in } if ( !fSilent ) { + printf( "Problem \"%s\" is ", p->pSpec ); if ( RetValue == 0 ) - printf( "Problem is SAT (solved by %d) ", RetEngine ); + printf( "SAT (solved by %d).", RetEngine ); else if ( RetValue == 1 ) - printf( "Problem is UNSAT (solved by %d) ", RetEngine ); + printf( "UNSAT (solved by %d).", RetEngine ); else if ( RetValue == -1 ) - printf( "Problem is UNDECIDED " ); + printf( "UNDECIDED." ); else assert( 0 ); printf( " " ); Abc_PrintTime( 1, "Time", Abc_Clock() - clkTotal ); diff --git a/src/proof/ssw/sswRarity.c b/src/proof/ssw/sswRarity.c index 1b7cab23de..679d30666b 100644 --- a/src/proof/ssw/sswRarity.c +++ b/src/proof/ssw/sswRarity.c @@ -1040,8 +1040,10 @@ int Ssw_RarSimulate( Aig_Man_t * pAig, Ssw_RarPars_t * pPars ) Abc_Print( 1, "Simulated %d frames for %d rounds with %d restarts.\n", pPars->nFrames, nNumRestart * pPars->nRestart + r, nNumRestart ); pAig->pSeqModel = Ssw_RarDeriveCex( p, r * p->pPars->nFrames + f, p->iFailPo, p->iFailPat, pPars->fVerbose ); // print final report - Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", pAig->pSeqModel->iPo, pAig->pName, pAig->pSeqModel->iFrame ); - Abc_PrintTime( 1, "Time", Abc_Clock() - clkTotal ); + if ( !pPars->fSilent ) { + Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", pAig->pSeqModel->iPo, pAig->pName, pAig->pSeqModel->iFrame ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clkTotal ); + } goto finish; } timeLastSolved = Abc_Clock(); From 1bf21626c0cca81592fdea2a073c1715b37e17bc Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Oct 2023 11:04:35 -0700 Subject: [PATCH 28/67] Bug fix. --- src/sat/glucose/Glucose.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/glucose/Glucose.cpp b/src/sat/glucose/Glucose.cpp index cfb388de66..d878e0d172 100644 --- a/src/sat/glucose/Glucose.cpp +++ b/src/sat/glucose/Glucose.cpp @@ -1124,7 +1124,7 @@ lbool Solver::search(int nof_conflicts) return l_False; } // Perform clause database reduction ! - if(conflicts>=curRestart* nbclausesbeforereduce) + if(conflicts>=curRestart* nbclausesbeforereduce && learnts.size()>0) { assert(learnts.size()>0); From 5de12aa6b3a91850596326954eaca0c997cc499e Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 23 Oct 2023 11:30:44 -0700 Subject: [PATCH 29/67] Experiments with SAT solving. --- src/base/io/io.c | 13 +++++++++---- src/base/io/ioUtil.c | 33 ++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/base/io/io.c b/src/base/io/io.c index f988a00785..55a02dee29 100644 --- a/src/base/io/io.c +++ b/src/base/io/io.c @@ -1224,17 +1224,21 @@ int IoCommandReadTruth( Abc_Frame_t * pAbc, int argc, char ** argv ) ***********************************************************************/ int IoCommandReadCnf( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Vec_Ptr_t * Io_FileReadCnf( char * pFileName ); + extern Vec_Ptr_t * Io_FileReadCnf( char * pFileName, int fMulti ); FILE * pFile; Abc_Ntk_t * pNtk; Vec_Ptr_t * vSops; + int fMulti = 0; int c; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "mh" ) ) != EOF ) { switch ( c ) { + case 'm': + fMulti ^= 1; + break; case 'h': goto usage; default: @@ -1253,7 +1257,7 @@ int IoCommandReadCnf( Abc_Frame_t * pAbc, int argc, char ** argv ) } else fclose( pFile ); - vSops = Io_FileReadCnf( argv[globalUtilOptind] ); + vSops = Io_FileReadCnf( argv[globalUtilOptind], fMulti ); if ( Vec_PtrSize(vSops) == 0 ) { Vec_PtrFreeFree( vSops ); @@ -1273,8 +1277,9 @@ int IoCommandReadCnf( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - fprintf( pAbc->Err, "usage: read_cnf [-h] \n" ); + fprintf( pAbc->Err, "usage: read_cnf [-mh] \n" ); fprintf( pAbc->Err, "\t creates network with one node\n" ); + fprintf( pAbc->Err, "\t-m : toggles generating multi-output network [default = %s]\n", fMulti? "yes":"no" ); fprintf( pAbc->Err, "\t-h : prints the command summary\n" ); fprintf( pAbc->Err, "\tfile : file name with the truth table\n" ); return 1; diff --git a/src/base/io/ioUtil.c b/src/base/io/ioUtil.c index d11ee74080..eee2dda538 100644 --- a/src/base/io/ioUtil.c +++ b/src/base/io/ioUtil.c @@ -931,8 +931,9 @@ void Io_TransformSF2PLA( char * pNameIn, char * pNameOut ) SeeAlso [] ***********************************************************************/ -char * Io_ConvertNumsToSop( Vec_Wec_t * vNums, int nVars ) +Vec_Ptr_t * Io_ConvertNumsToSop( Vec_Wec_t * vNums, int nVars ) { + Vec_Ptr_t * vSops = Vec_PtrAlloc(1); Vec_Int_t * vLevel; int i, k, Num; int nSize = (nVars + 3)*Vec_WecSize(vNums); char * pStr = ABC_ALLOC( char, nSize+1 ); @@ -947,11 +948,30 @@ char * Io_ConvertNumsToSop( Vec_Wec_t * vNums, int nVars ) pCube[nVars+1] = '0'; pCube[nVars+2] = '\n'; } - return pStr; + Vec_PtrPush( vSops, pStr ); + return vSops; } -Vec_Ptr_t * Io_FileReadCnf( char * pFileName ) +Vec_Ptr_t * Io_ConvertNumsToSopMulti( Vec_Wec_t * vNums, int nVars ) { - Vec_Ptr_t * vSops = Vec_PtrAlloc( 1 ); + Vec_Ptr_t * vSops = Vec_PtrAlloc( Vec_WecSize(vNums) ); + Vec_Int_t * vLevel; int i, k, Num; + Vec_WecForEachLevel( vNums, vLevel, i ) + { + char * pCube = ABC_ALLOC( char, nVars + 4 ); + memset( pCube, '-', nVars ); + Vec_IntForEachEntry( vLevel, Num, k ) + pCube[Abc_Lit2Var(Num)] = '0' + Abc_LitIsCompl(Num); + pCube[nVars+0] = ' '; + pCube[nVars+1] = '0'; + pCube[nVars+2] = '\n'; + pCube[nVars+3] = '\0'; + Vec_PtrPush( vSops, pCube ); + } + return vSops; +} +Vec_Ptr_t * Io_FileReadCnf( char * pFileName, int fMulti ) +{ + Vec_Ptr_t * vSops = NULL; Vec_Wec_t * vNums = Vec_WecAlloc( 100 ); Vec_Int_t * vLevel; char * pThis, pLine[10000]; @@ -1002,7 +1022,10 @@ Vec_Ptr_t * Io_FileReadCnf( char * pFileName ) if ( nClas != Vec_WecSize(vNums) ) printf( "Warning: The number of clauses (%d) listed is different from the actual number (%d).\n", nClas, Vec_WecSize(vNums) ); //Vec_WecPrint( vNums, 0 ); - Vec_PtrPush( vSops, Io_ConvertNumsToSop(vNums, nVars) ); + if ( fMulti ) + vSops = Io_ConvertNumsToSopMulti(vNums, nVars); + else + vSops = Io_ConvertNumsToSop(vNums, nVars); Vec_WecFree( vNums ); return vSops; } From 04dba9eed9eed7702ddcea4862cc4dc8818d1db8 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 6 Nov 2023 17:35:41 -0800 Subject: [PATCH 30/67] Adding callback for wire caps during sizing. --- src/map/scl/scl.c | 4 ++-- src/map/scl/sclDnsize.c | 7 ++++--- src/map/scl/sclSize.c | 14 +++++++++----- src/map/scl/sclSize.h | 7 ++++--- src/map/scl/sclUpsize.c | 7 ++++--- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/map/scl/scl.c b/src/map/scl/scl.c index 8671d958e6..29798f8fae 100644 --- a/src/map/scl/scl.c +++ b/src/map/scl/scl.c @@ -1604,7 +1604,7 @@ int Scl_CommandUpsize( Abc_Frame_t * pAbc, int argc, char **argv ) return 1; } - Abc_SclUpsizePerform( (SC_Lib *)pAbc->pLibScl, pNtk, pPars ); + Abc_SclUpsizePerform( (SC_Lib *)pAbc->pLibScl, pNtk, pPars, NULL ); return 0; usage: @@ -1781,7 +1781,7 @@ int Scl_CommandDnsize( Abc_Frame_t * pAbc, int argc, char **argv ) return 1; } - Abc_SclDnsizePerform( (SC_Lib *)pAbc->pLibScl, pNtk, pPars ); + Abc_SclDnsizePerform( (SC_Lib *)pAbc->pLibScl, pNtk, pPars, NULL ); return 0; usage: diff --git a/src/map/scl/sclDnsize.c b/src/map/scl/sclDnsize.c index 5be9e3a348..35f2c8247d 100644 --- a/src/map/scl/sclDnsize.c +++ b/src/map/scl/sclDnsize.c @@ -239,7 +239,7 @@ void Abc_SclDnsizePrint( SC_Man * p, int Iter, int nAttempts, int nOverlaps, int SeeAlso [] ***********************************************************************/ -void Abc_SclDnsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ) +void Abc_SclDnsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, void * pFuncFanin ) { SC_Man * p; Abc_Obj_t * pObj; @@ -261,6 +261,7 @@ void Abc_SclDnsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPa // prepare the manager; collect init stats p = Abc_SclManStart( pLib, pNtk, pPars->fUseWireLoads, pPars->fUseDept, pPars->DelayUser, pPars->BuffTreeEst ); + p->pFuncFanin = (float (*)(void *, Abc_Obj_t *, Abc_Obj_t *, int, int))pFuncFanin; p->timeTotal = Abc_Clock(); assert( p->vGatesBest == NULL ); p->vGatesBest = Vec_IntDup( p->pNtk->vGates ); @@ -357,12 +358,12 @@ void Abc_SclDnsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPa SeeAlso [] ***********************************************************************/ -void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ) +void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, void * pFuncFanin ) { Abc_Ntk_t * pNtkNew = pNtk; if ( pNtk->nBarBufs2 > 0 ) pNtkNew = Abc_NtkDupDfsNoBarBufs( pNtk ); - Abc_SclDnsizePerformInt( pLib, pNtkNew, pPars ); + Abc_SclDnsizePerformInt( pLib, pNtkNew, pPars, pFuncFanin ); if ( pNtk->nBarBufs2 > 0 ) Abc_SclTransferGates( pNtk, pNtkNew ); if ( pNtk->nBarBufs2 > 0 ) diff --git a/src/map/scl/sclSize.c b/src/map/scl/sclSize.c index e09c56e67d..b3bc2828de 100644 --- a/src/map/scl/sclSize.c +++ b/src/map/scl/sclSize.c @@ -270,21 +270,25 @@ void Abc_SclTimeNtkPrint( SC_Man * p, int fShowAll, int fPrintPath ) SeeAlso [] ***********************************************************************/ -static inline void Abc_SclTimeFanin( SC_Man * p, SC_Timing * pTime, Abc_Obj_t * pObj, Abc_Obj_t * pFanin ) +static inline void Abc_SclTimeFanin( SC_Man * p, SC_Timing * pTime, Abc_Obj_t * pObj, Abc_Obj_t * pFanin, int k ) { SC_Pair * pArrIn = Abc_SclObjTime( p, pFanin ); SC_Pair * pSlewIn = Abc_SclObjSlew( p, pFanin ); SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); SC_Pair * pArrOut = Abc_SclObjTime( p, pObj ); // modified SC_Pair * pSlewOut = Abc_SclObjSlew( p, pObj ); // modified + if ( p->pFuncFanin ) pLoad->fall += p->pFuncFanin(p, pObj, pFanin, k, 0); + if ( p->pFuncFanin ) pLoad->rise += p->pFuncFanin(p, pObj, pFanin, k, 1); Scl_LibPinArrival( pTime, pArrIn, pSlewIn, pLoad, pArrOut, pSlewOut ); } -static inline void Abc_SclDeptFanin( SC_Man * p, SC_Timing * pTime, Abc_Obj_t * pObj, Abc_Obj_t * pFanin ) +static inline void Abc_SclDeptFanin( SC_Man * p, SC_Timing * pTime, Abc_Obj_t * pObj, Abc_Obj_t * pFanin, int k ) { SC_Pair * pDepIn = Abc_SclObjDept( p, pFanin ); // modified SC_Pair * pSlewIn = Abc_SclObjSlew( p, pFanin ); SC_Pair * pLoad = Abc_SclObjLoad( p, pObj ); SC_Pair * pDepOut = Abc_SclObjDept( p, pObj ); + if ( p->pFuncFanin ) pLoad->fall += p->pFuncFanin(p, pObj, pFanin, k, 0); + if ( p->pFuncFanin ) pLoad->rise += p->pFuncFanin(p, pObj, pFanin, k, 1); Scl_LibPinDeparture( pTime, pDepIn, pSlewIn, pLoad, pDepOut ); } static inline void Abc_SclDeptObj( SC_Man * p, Abc_Obj_t * pObj ) @@ -298,7 +302,7 @@ static inline void Abc_SclDeptObj( SC_Man * p, Abc_Obj_t * pObj ) 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_SclDeptFanin( p, pTime, pFanout, pObj, Abc_NodeFindFanin(pFanout, pObj) ); } } static inline float Abc_SclObjLoadValue( SC_Man * p, Abc_Obj_t * pObj ) @@ -368,9 +372,9 @@ void Abc_SclTimeNode( SC_Man * p, Abc_Obj_t * pObj, int fDept ) { pTime = Scl_CellPinTime( pCell, k ); if ( fDept ) - Abc_SclDeptFanin( p, pTime, pObj, pFanin ); + Abc_SclDeptFanin( p, pTime, pObj, pFanin, k ); else - Abc_SclTimeFanin( p, pTime, pObj, pFanin ); + Abc_SclTimeFanin( p, pTime, pObj, pFanin, k ); } if ( p->EstLoadMax && Value > 1 ) { diff --git a/src/map/scl/sclSize.h b/src/map/scl/sclSize.h index 3ec0d83e35..133ae6647b 100644 --- a/src/map/scl/sclSize.h +++ b/src/map/scl/sclSize.h @@ -95,6 +95,7 @@ struct SC_Man_ abctime timeSize; // incremental sizing abctime timeTime; // timing update abctime timeOther; // everything else + float (*pFuncFanin)(void * p, Abc_Obj_t * pObj, Abc_Obj_t * pFanin, int iFanin, int fRise); // called to get info about the node's fanin }; //////////////////////////////////////////////////////////////////////// @@ -127,7 +128,7 @@ static inline double Abc_SclObjSlackMax( SC_Man * p, Abc_Obj_t * pObj, float static inline void Abc_SclObjDupFanin( SC_Man * p, Abc_Obj_t * pObj ) { assert( Abc_ObjIsCo(pObj) ); *Abc_SclObjTime(p, pObj) = *Abc_SclObjTime(p, Abc_ObjFanin0(pObj)); } static inline float Abc_SclObjInDrive( SC_Man * p, Abc_Obj_t * pObj ) { return Vec_FltEntry( p->vInDrive, pObj->iData ); } 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; } //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// @@ -551,7 +552,7 @@ extern int Abc_SclCheckNtk( Abc_Ntk_t * p, int fVerbose ); extern Abc_Ntk_t * Abc_SclPerformBuffering( Abc_Ntk_t * p, int DegreeR, int Degree, int fUseInvs, int fVerbose ); extern Abc_Ntk_t * Abc_SclBufPerform( Abc_Ntk_t * pNtk, int FanMin, int FanMax, int fBufPis, int fSkipDup, int fVerbose ); /*=== sclDnsize.c ===============================================================*/ -extern void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ); +extern void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, void * pFuncFanin ); /*=== sclLoad.c ===============================================================*/ extern Vec_Flt_t * Abc_SclFindWireCaps( SC_WireLoad * pWL, int nFanoutMax ); extern float Abc_SclFindWireLoad( Vec_Flt_t * vWireCaps, int nFans ); @@ -573,7 +574,7 @@ extern void Abc_SclTimePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, int nT extern void Abc_SclPrintBuffers( SC_Lib * pLib, Abc_Ntk_t * pNtk, int fVerbose ); /*=== sclUpsize.c ===============================================================*/ extern int Abc_SclCountNearCriticalNodes( SC_Man * p ); -extern void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ); +extern void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, void * pFuncFanin ); /*=== sclUtil.c ===============================================================*/ extern void Abc_SclMioGates2SclGates( SC_Lib * pLib, Abc_Ntk_t * p ); extern void Abc_SclSclGates2MioGates( SC_Lib * pLib, Abc_Ntk_t * p ); diff --git a/src/map/scl/sclUpsize.c b/src/map/scl/sclUpsize.c index 5c63073520..822278a338 100644 --- a/src/map/scl/sclUpsize.c +++ b/src/map/scl/sclUpsize.c @@ -865,7 +865,7 @@ void Abc_SclUpsizeRemoveDangling( SC_Man * p, Abc_Ntk_t * pNtk ) SeeAlso [] ***********************************************************************/ -void Abc_SclUpsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ) +void Abc_SclUpsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, void * pFuncFanin ) { SC_Man * p; Vec_Int_t * vPathPos = NULL; // critical POs @@ -891,6 +891,7 @@ void Abc_SclUpsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPa pPars->Window += (Abc_NtkNodeNum(pNtk) > 40000); // prepare the manager; collect init stats p = Abc_SclManStart( pLib, pNtk, pPars->fUseWireLoads, pPars->fUseDept, 0, pPars->BuffTreeEst ); + p->pFuncFanin = (float (*)(void *, Abc_Obj_t *, Abc_Obj_t *, int, int))pFuncFanin; p->timeTotal = Abc_Clock(); assert( p->vGatesBest == NULL ); p->vGatesBest = Vec_IntDup( p->pNtk->vGates ); @@ -1024,12 +1025,12 @@ void Abc_SclUpsizePerformInt( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPa SeeAlso [] ***********************************************************************/ -void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars ) +void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_SizePars * pPars, void * pFuncFanin ) { Abc_Ntk_t * pNtkNew = pNtk; if ( pNtk->nBarBufs2 > 0 ) pNtkNew = Abc_NtkDupDfsNoBarBufs( pNtk ); - Abc_SclUpsizePerformInt( pLib, pNtkNew, pPars ); + Abc_SclUpsizePerformInt( pLib, pNtkNew, pPars, pFuncFanin ); if ( pNtk->nBarBufs2 > 0 ) Abc_SclTransferGates( pNtk, pNtkNew ); if ( pNtk->nBarBufs2 > 0 ) From eb264c5d22533fdc7315c1565d8ed286e0237087 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 13 Nov 2023 17:19:54 -0800 Subject: [PATCH 31/67] Suggested fixes. --- src/aig/aig/aigOper.c | 2 +- src/base/abci/abcNtbdd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aig/aig/aigOper.c b/src/aig/aig/aigOper.c index 4fe2cd8c47..d6f02a6e0b 100644 --- a/src/aig/aig/aigOper.c +++ b/src/aig/aig/aigOper.c @@ -453,7 +453,7 @@ Aig_Obj_t * Aig_Miter( Aig_Man_t * p, Vec_Ptr_t * vPairs ) Aig_Obj_t * Aig_MiterTwo( Aig_Man_t * p, Vec_Ptr_t * vNodes1, Vec_Ptr_t * vNodes2 ) { int i; - assert( vNodes1->nSize > 0 && vNodes1->nSize > 0 ); + assert( vNodes1->nSize > 0 && vNodes2->nSize > 0 ); assert( vNodes1->nSize == vNodes2->nSize ); for ( i = 0; i < vNodes1->nSize; i++ ) vNodes1->pArray[i] = Aig_Not( Aig_Exor( p, (Aig_Obj_t *)vNodes1->pArray[i], (Aig_Obj_t *)vNodes2->pArray[i] ) ); diff --git a/src/base/abci/abcNtbdd.c b/src/base/abci/abcNtbdd.c index 9de88980df..0676a7d0e9 100644 --- a/src/base/abci/abcNtbdd.c +++ b/src/base/abci/abcNtbdd.c @@ -237,7 +237,7 @@ Abc_Obj_t * Abc_NodeBddToMuxes_rec( DdManager * dd, DdNode * bFunc, Abc_Ntk_t * { Abc_Obj_t * pNodeNew, * pNodeNew0, * pNodeNew1, * pNodeNewC; assert( !Cudd_IsComplement(bFunc) ); - assert( b1 == a1 ); + //assert( b1 == a1 ); if ( bFunc == a1 ) return Abc_NtkCreateNodeConst1(pNtkNew); if ( bFunc == a0 ) From 6ca7eab466342ba8187c188328736d6a44d52199 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 14 Nov 2023 12:58:03 -0800 Subject: [PATCH 32/67] Prototype of integrating decomposition into "if". --- src/base/abci/abc.c | 10 +++++++--- src/base/abci/abcIf.c | 33 +++++++++++++++++++++++++++++++-- src/map/if/if.h | 1 + src/map/if/ifCut.c | 2 +- src/map/if/ifMap.c | 34 ++++++++++++++++++++++++++++++++-- 5 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 0558eefa4d..c8e2b1ef8a 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -19447,7 +19447,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) If_ManSetDefaultPars( pPars ); pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut(); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYDEWSqaflepmrsdbgxyuojiktncvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYDEWSqaflepmrsdbgxyzuojiktncvh" ) ) != EOF ) { switch ( c ) { @@ -19652,6 +19652,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'y': pPars->fUserRecLib ^= 1; break; + case 'z': + pPars->fUserLutDec ^= 1; + break; case 'u': pPars->fUserSesLib ^= 1; break; @@ -19807,7 +19810,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) pPars->pLutLib = NULL; } // modify for delay optimization - if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut ) + if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut || pPars->fUserLutDec ) { pPars->fTruth = 1; pPars->fCutMin = 1; @@ -19953,7 +19956,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) sprintf(LutSize, "library" ); else sprintf(LutSize, "%d", pPars->nLutSize ); - Abc_Print( -2, "usage: if [-KCFAGRNTXY num] [-DEW float] [-S str] [-qarlepmsdbgxyuojiktncvh]\n" ); + Abc_Print( -2, "usage: if [-KCFAGRNTXY num] [-DEW float] [-S str] [-qarlepmsdbgxyzuojiktncvh]\n" ); Abc_Print( -2, "\t performs FPGA technology mapping of the network\n" ); Abc_Print( -2, "\t-K num : the number of LUT inputs (2 < num < %d) [default = %s]\n", IF_MAX_LUTSIZE+1, LutSize ); Abc_Print( -2, "\t-C num : the max number of priority cuts (0 < num < 2^12) [default = %d]\n", pPars->nCutsMax ); @@ -19982,6 +19985,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-g : toggles delay optimization by SOP balancing [default = %s]\n", pPars->fDelayOpt? "yes": "no" ); Abc_Print( -2, "\t-x : toggles delay optimization by DSD balancing [default = %s]\n", pPars->fDsdBalance? "yes": "no" ); Abc_Print( -2, "\t-y : toggles delay optimization with recorded library [default = %s]\n", pPars->fUserRecLib? "yes": "no" ); + Abc_Print( -2, "\t-z : toggles delay optimization with LUT decomposition [default = %s]\n", pPars->fUserLutDec? "yes": "no" ); Abc_Print( -2, "\t-u : toggles delay optimization with SAT-based library [default = %s]\n", pPars->fUserSesLib? "yes": "no" ); Abc_Print( -2, "\t-o : toggles using buffers to decouple combinational outputs [default = %s]\n", pPars->fUseBuffs? "yes": "no" ); Abc_Print( -2, "\t-j : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck07? "yes": "no" ); diff --git a/src/base/abci/abcIf.c b/src/base/abci/abcIf.c index 491e2c140a..e92a2282ee 100644 --- a/src/base/abci/abcIf.c +++ b/src/base/abci/abcIf.c @@ -116,7 +116,7 @@ Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars ) pPars->pTimesReq = Abc_NtkGetCoRequiredFloats(pNtk); // update timing info to reflect logic level - if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib) && pNtk->pManTime ) + if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib || pPars->fUserLutDec) && pNtk->pManTime ) { int c; if ( pNtk->AndGateDelay == 0.0 ) @@ -426,6 +426,30 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC return Abc_NodeBuildFromMiniInt( pMan, p->vArray, If_CutLeaveNum(pCut) ); } +/**Function************************************************************* + + Synopsis [Implements decomposed LUT-structure of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Hop_Obj_t * Abc_DecRecordToHop( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCutBest, If_Obj_t * pIfObj, Vec_Int_t * vCover ) +{ + // get the truth table + // perform LUT-decomposition and return the LUT-structure + // convert the LUT-structure into a set of logic nodes in Abc_Ntk_t + + // this is a placeholder, which takes the truth table and converts it into an AIG without LUT-decomposition + extern Hop_Obj_t * Kit_TruthToHop( Hop_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory ); + word * pTruth = If_CutTruthW(pIfMan, pCutBest); + assert( !pIfMan->pPars->fUseTtPerm ); + return Kit_TruthToHop( (Hop_Man_t *)pMan, (unsigned *)pTruth, If_CutLeaveNum(pCutBest), vCover ); +} + /**Function************************************************************* Synopsis [Derive one node after FPGA mapping.] @@ -464,7 +488,7 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t pNodeNew = Abc_NtkCreateNode( pNtkNew ); // if ( pIfMan->pPars->pLutLib && pIfMan->pPars->pLutLib->fVarPinDelays ) if ( !pIfMan->pPars->fDelayOpt && !pIfMan->pPars->fDelayOptLut && !pIfMan->pPars->fDsdBalance && !pIfMan->pPars->fUseTtPerm && - !pIfMan->pPars->pLutStruct && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->nGateSize ) + !pIfMan->pPars->pLutStruct && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->fUserLutDec && !pIfMan->pPars->nGateSize ) If_CutRotatePins( pIfMan, pCutBest ); if ( pIfMan->pPars->fUseCnfs || pIfMan->pPars->fUseMv ) { @@ -524,6 +548,11 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t extern Hop_Obj_t * Abc_RecToHop3( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj ); pNodeNew->pData = Abc_RecToHop3( (Hop_Man_t *)pNtkNew->pManFunc, pIfMan, pCutBest, pIfObj ); } + else if ( pIfMan->pPars->fUserLutDec ) + { + extern Hop_Obj_t * Abc_DecRecordToHop( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj, Vec_Int_t * vMemory ); + pNodeNew->pData = Abc_DecRecordToHop( (Hop_Man_t *)pNtkNew->pManFunc, pIfMan, pCutBest, pIfObj, vCover ); + } else { extern Hop_Obj_t * Kit_TruthToHop( Hop_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory ); diff --git a/src/map/if/if.h b/src/map/if/if.h index a72da9b959..93cb0f6caf 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -126,6 +126,7 @@ struct If_Par_t_ int fDsdBalance; // special delay optimization int fUserRecLib; // use recorded library int fUserSesLib; // use SAT-based synthesis + int fUserLutDec; // use LUT-based decomposition int fBidec; // use bi-decomposition int fUse34Spec; // use specialized matching int fUseBat; // use one specialized feature diff --git a/src/map/if/ifCut.c b/src/map/if/ifCut.c index e3d47f1c6d..f4f72d1c8d 100644 --- a/src/map/if/ifCut.c +++ b/src/map/if/ifCut.c @@ -765,7 +765,7 @@ void If_CutSort( If_Man_t * p, If_Set_t * pCutSet, If_Cut_t * pCut ) if ( !pCut->fUseless && (p->pPars->fUseDsd || p->pPars->pFuncCell2 || p->pPars->fUseBat || - p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || + p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fEnableCheck07 || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->fUseDsdTune || p->pPars->fEnableCheck75 || p->pPars->fEnableCheck75u || p->pPars->fUseCheck1 || p->pPars->fUseCheck2) ) { diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index b3a4caf665..4a5210e923 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -148,6 +148,32 @@ int * If_CutArrTimeProfile( If_Man_t * p, If_Cut_t * pCut ) return p->pArrTimeProfile; } + +/**Function************************************************************* + + Synopsis [Returns the node's delay if its cut it LUT-decomposed.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_CutDelayLutDec( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj ) +{ + // get the truth table + // get the cut leaves' arrival times + // run LUT-decomposition in the evaluation mode + // return expected arrival time at the output + + // this is a placeholder code, which is assume the cut has unit delay + int i, ArrTimes = 0; + for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) + ArrTimes = Abc_MaxInt( ArrTimes, (int)If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay ); + return ArrTimes + 1; +} + /**Function************************************************************* Synopsis [Finds the best cut for the given node.] @@ -166,7 +192,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep If_Cut_t * pCut0R, * pCut1R; int fFunc0R, fFunc1R; int i, k, v, iCutDsd, fChange; - int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || + int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fUseDsdTune || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->pLutStruct || p->pPars->pFuncCell2 || p->pPars->fUseCheck1 || p->pPars->fUseCheck2; int fUseAndCut = (p->pPars->nAndDelay > 0) || (p->pPars->nAndArea > 0); assert( !If_ObjIsAnd(pObj->pFanin0) || pObj->pFanin0->pCutSet->nCuts > 0 ); @@ -208,6 +234,8 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->fUseless = 1; } } + else if ( p->pPars->fUserLutDec ) + pCut->Delay = If_CutDelayLutDec( p, pCut, pObj ); else if ( p->pPars->fDelayOptLut ) pCut->Delay = If_CutLutBalanceEval( p, pCut ); else if( p->pPars->nGateSize > 0 ) @@ -436,6 +464,8 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->fUseless = 1; } } + else if ( p->pPars->fUserLutDec ) + pCut->Delay = If_CutDelayLutDec( p, pCut, pObj ); else if ( p->pPars->fDelayOptLut ) pCut->Delay = If_CutLutBalanceEval( p, pCut ); else if( p->pPars->nGateSize > 0 ) @@ -507,7 +537,7 @@ void If_ObjPerformMappingChoice( If_Man_t * p, If_Obj_t * pObj, int Mode, int fP If_Set_t * pCutSet; If_Obj_t * pTemp; If_Cut_t * pCutTemp, * pCut; - int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUse34Spec; + int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fUse34Spec; assert( pObj->pEquiv != NULL ); // prepare From 1632dc0d4ec9c917a44ce02965d83a4d6f948f37 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Wed, 15 Nov 2023 18:38:00 +0100 Subject: [PATCH 33/67] First version of ACD --- Makefile | 5 +- src/acd/ac_decomposition.hpp | 1500 ++++++++++++++++++++++++++++++++ src/acd/ac_wrapper.cpp | 69 ++ src/acd/ac_wrapper.h | 23 + src/acd/kitty_algorithm.hpp | 119 +++ src/acd/kitty_constants.hpp | 91 ++ src/acd/kitty_constructors.hpp | 92 ++ src/acd/kitty_dynamic_tt.hpp | 147 ++++ src/acd/kitty_operations.hpp | 333 +++++++ src/acd/kitty_operators.hpp | 86 ++ src/acd/kitty_static_tt.hpp | 131 +++ src/acd/module.make | 1 + src/base/abci/abc.c | 14 +- src/base/abci/abcIf.c | 158 +++- src/map/if/if.h | 11 +- src/map/if/ifCore.c | 18 + src/map/if/ifCut.c | 6 +- src/map/if/ifDelay.c | 126 +++ src/map/if/ifMap.c | 47 +- src/map/if/ifTime.c | 6 + 20 files changed, 2916 insertions(+), 67 deletions(-) create mode 100644 src/acd/ac_decomposition.hpp create mode 100644 src/acd/ac_wrapper.cpp create mode 100644 src/acd/ac_wrapper.h create mode 100644 src/acd/kitty_algorithm.hpp create mode 100644 src/acd/kitty_constants.hpp create mode 100644 src/acd/kitty_constructors.hpp create mode 100644 src/acd/kitty_dynamic_tt.hpp create mode 100644 src/acd/kitty_operations.hpp create mode 100644 src/acd/kitty_operators.hpp create mode 100644 src/acd/kitty_static_tt.hpp create mode 100644 src/acd/module.make diff --git a/Makefile b/Makefile index 3976cf7b15..d770c3faf4 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ OS := $(shell uname -s) MODULES := \ $(wildcard src/ext*) \ + src/acd \ 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 \ @@ -56,7 +57,7 @@ ARCHFLAGS := $(ARCHFLAGS) OPTFLAGS ?= -g -O -CFLAGS += -Wall -Wno-unused-function -Wno-write-strings -Wno-sign-compare $(ARCHFLAGS) +CFLAGS += -std=c17 -Wall -Wno-unused-function -Wno-write-strings -Wno-sign-compare $(ARCHFLAGS) ifneq ($(findstring arm,$(shell uname -m)),) CFLAGS += -DABC_MEMALIGN=4 endif @@ -151,7 +152,7 @@ ifdef ABC_USE_LIBSTDCXX endif $(info $(MSG_PREFIX)Using CFLAGS=$(CFLAGS)) -CXXFLAGS += $(CFLAGS) +CXXFLAGS += $(CFLAGS) -std=c++17 SRC := GARBAGE := core core.* *.stackdump ./tags $(PROG) arch_flags diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp new file mode 100644 index 0000000000..4f94bcba4b --- /dev/null +++ b/src/acd/ac_decomposition.hpp @@ -0,0 +1,1500 @@ +/* mockturtle: C++ logic network library + * Copyright (C) 2018-2023 EPFL + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/*! + \file ac_decomposition.hpp + \brief Ashenhurst-Curtis decomposition + + \author Alessandro Tempia Calvino +*/ + +#ifndef _ACD_H_ +#define _ACD_H_ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "kitty_constants.hpp" +#include "kitty_constructors.hpp" +#include "kitty_static_tt.hpp" +#include "kitty_dynamic_tt.hpp" +#include "kitty_operations.hpp" +#include "kitty_operators.hpp" + +namespace mockturtle +{ + +/*! \brief Parameters for ac_decomposition */ +struct ac_decomposition_params +{ + /*! \brief LUT size for decomposition. */ + uint32_t lut_size{ 6 }; + + /*! \brief Maximum number of iterations for covering. */ + uint32_t max_iter{ 5000 }; +}; + +/*! \brief Statistics for ac_decomposition */ +struct ac_decomposition_stats +{ + uint32_t num_luts{ 0 }; + uint32_t num_edges{ 0 }; + uint32_t num_levels{ 0 }; +}; + +struct ac_decomposition_result +{ + kitty::dynamic_truth_table tt; + std::vector support; +}; + +template +class ac_decomposition_impl +{ +private: + struct encoding_matrix + { + uint64_t column{ 0 }; + uint32_t cost{ 0 }; + uint32_t index{ 0 }; + uint32_t sort_cost{ 0 }; + }; + +private: + static constexpr uint32_t max_num_vars = 8; + using STT = kitty::static_truth_table; + +public: + explicit ac_decomposition_impl( TT const& tt, uint32_t num_vars, ac_decomposition_params const& ps, ac_decomposition_stats* pst = nullptr ) + : num_vars( num_vars ), ps( ps ), pst( pst ), permutations( num_vars ) + { + tt_start = tt; + std::iota( permutations.begin(), permutations.end(), 0 ); + } + + /*! \brief Runs ACD using late arriving variables */ + int run( unsigned delay_profile ) + { + /* truth table is too large for the settings */ + if ( num_vars > max_num_vars ) + { + return -1; + } + + uint32_t late_arriving = __builtin_popcount( delay_profile ); + + /* return a high cost if too many late arriving variables */ + if ( late_arriving > ps.lut_size / 2 || late_arriving > 3 ) + { + return -1; + } + + /* convert to static TT */ + best_tt = kitty::extend_to( tt_start ); + best_multiplicity = UINT32_MAX; + uint32_t best_cost = UINT32_MAX; + + /* permute late arriving variables to be the least significant */ + reposition_late_arriving_variables( delay_profile, late_arriving ); + + /* run ACD trying different bound sets and free sets */ + uint32_t free_set_size = late_arriving; + uint32_t offset = std::max( static_cast( late_arriving ), 1u ); + for ( uint32_t i = offset; i <= ps.lut_size / 2 && i <= 3; ++i ) + { + auto evaluate_fn = [&]( STT const& tt ) { return column_multiplicity( tt, i ); }; + auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, evaluate_fn, false ); + + /* add cost if not support reducing */ + uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; + /* check for feasible solution that improves the cost */ + if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost ) + { + best_tt = tt_p; + permutations = perm; + best_multiplicity = cost; + best_cost = cost + additional_cost; + free_set_size = i; + } + } + + if ( best_multiplicity == UINT32_MAX ) + return -1; + + /* compute isets */ + // std::vector isets = compute_isets( free_set_size ); + + // generate_support_minimization_encodings(); + // solve_min_support_exact( isets, free_set_size ); + + /* unfeasible decomposition */ + // if ( best_bound_sets.empty() ) + // { + // return -1; + // } + + pst->num_luts = ps.lut_size - free_set_size; + best_free_set = free_set_size; + + /* TODO generate decomposition only when returning the result */ + // dec_result = generate_decomposition( free_set_size ); + + /* TODO: change return value */ + return 0; + } + + int compute_decomposition() + { + if ( best_multiplicity == UINT32_MAX ) + return -1; + + /* compute isets */ + std::vector isets = compute_isets( best_free_set ); + + generate_support_minimization_encodings(); + solve_min_support_exact( isets, best_free_set ); + + /* unfeasible decomposition */ + if ( best_bound_sets.empty() ) + { + return -1; + } + + return 0; + } + + unsigned get_profile() + { + unsigned profile = 0; + + if ( best_free_set > num_vars ) + return -1; + + for ( uint32_t i = 0; i < best_free_set; ++i ) + { + profile |= 1 << permutations[i]; + } + + return profile; + } + + std::vector get_result() + { + return dec_result; + } + + void get_decomposition( unsigned char *decompArray ) + { + if ( best_free_set > num_vars ) + return; + + dec_result = generate_decomposition( best_free_set ); + return get_decomposition_abc( decompArray ); + } + +private: + uint32_t column_multiplicity( STT tt, uint32_t free_set_size ) + { + uint64_t multiplicity_set[4] = { 0u, 0u, 0u, 0u }; + uint32_t multiplicity = 0; + uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + + /* supports up to 64 values of free set (256 for |FS| == 3)*/ + assert( free_set_size <= 3 ); + + /* extract iset functions */ + if ( free_set_size == 1 ) + { + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < 32; ++j ) + { + multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0x3 ); + *it >>= 2; + } + ++it; + } + } + else if ( free_set_size == 2 ) + { + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < 16; ++j ) + { + multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0xF ); + *it >>= 4; + } + ++it; + } + } + else /* free set size 3 */ + { + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < 8; ++j ) + { + multiplicity_set[( *it >> 6 ) & 0x3] |= UINT64_C( 1 ) << ( *it & 0x3F ); + *it >>= 8; + } + ++it; + } + } + + multiplicity = __builtin_popcountl( multiplicity_set[0] ); + + if ( free_set_size == 3 ) + { + multiplicity += __builtin_popcountl( multiplicity_set[1] ); + multiplicity += __builtin_popcountl( multiplicity_set[2] ); + multiplicity += __builtin_popcountl( multiplicity_set[3] ); + } + + return multiplicity; + } + + template + std::tuple, uint32_t> enumerate_iset_combinations( uint32_t free_set_size, Fn&& fn, bool verbose = false ) + { + /* works up to 16 input truth tables */ + assert( num_vars <= 16 ); + + /* special case */ + STT tt = best_tt; + if ( num_vars <= free_set_size || free_set_size == 0 ) + { + return { tt, permutations, UINT32_MAX }; + } + + /* select k */ + // free_set_size = std::min( free_set_size, num_vars - free_set_size ); + + /* init permutation array */ + std::array perm, best_perm; + std::copy( permutations.begin(), permutations.begin() + num_vars, perm.begin() ); + best_perm = perm; + + /* TT with best cost */ + STT best = tt; + uint32_t best_cost = UINT32_MAX; + + /* enumerate combinations */ + if ( free_set_size == 1 ) + { + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size ); + } + + for ( uint32_t i = 1; i < num_vars; ++i ) + { + std::swap( perm[0], perm[i] ); + kitty::swap_inplace( tt, 0, i ); + + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size ); + } + } + } + else if ( free_set_size == 2 ) + { + for ( uint32_t i = 0; i < num_vars - 1; ++i ) + { + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size ); + } + + for ( uint32_t j = 2; j < num_vars - i; ++j ) + { + std::swap( perm[1], perm[j] ); + kitty::swap_inplace( tt, 1, j ); + + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size ); + } + } + + std::swap( perm[0], perm[num_vars - i - 1] ); + kitty::swap_inplace( tt, 0, num_vars - i - 1 ); + } + } + else if ( free_set_size == 3 ) + { + for ( uint32_t i = 0; i < num_vars - 2; ++i ) + { + for ( uint32_t j = i; j < num_vars - 2; ++j ) + { + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size ); + } + + for ( uint32_t k = 3; k < num_vars - j; ++k ) + { + std::swap( perm[2], perm[k] ); + kitty::swap_inplace( tt, 2, k ); + + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size ); + } + } + + std::swap( perm[1], perm[num_vars - j - 1] ); + kitty::swap_inplace( tt, 1, num_vars - j - 1 ); + } + + std::swap( perm[0], perm[num_vars - i - 1] ); + kitty::swap_inplace( tt, 0, num_vars - i - 1 ); + } + } + + std::vector res_perm( num_vars ); + std::copy( best_perm.begin(), best_perm.begin() + num_vars, res_perm.begin() ); + + return std::make_tuple( best, res_perm, best_cost ); + } + + template + std::tuple, uint32_t> enumerate_iset_combinations_offset( uint32_t free_set_size, uint32_t offset, Fn&& fn, bool verbose = false ) + { + STT tt = best_tt; + + /* TT with best cost */ + STT best_tt = tt; + uint32_t best_cost = UINT32_MAX; + + /* works up to 16 input truth tables */ + assert( num_vars <= 16 ); + + /* select k */ + free_set_size = std::min( free_set_size, num_vars - free_set_size ); + + /* special case */ + if ( num_vars <= free_set_size || free_set_size <= offset ) + { + if ( offset == free_set_size ) + { + best_cost = fn( tt ); + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << best_cost << " "; + print_perm( permutations.begin(), free_set_size ); + } + + return { tt, permutations, best_cost }; + } + else + { + return { tt, permutations, UINT32_MAX }; + } + } + + /* decrease combinations */ + free_set_size -= offset; + + /* init permutation array */ + std::array perm, best_perm; + std::copy( permutations.begin(), permutations.begin() + num_vars, perm.begin() ); + best_perm = perm; + + /* enumerate combinations */ + if ( free_set_size == 1 ) + { + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best_tt = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size + offset ); + } + + for ( uint32_t i = offset + 1; i < num_vars; ++i ) + { + std::swap( perm[offset], perm[i] ); + kitty::swap_inplace( tt, offset, i ); + + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best_tt = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size + offset ); + } + } + } + else if ( free_set_size == 2 ) + { + for ( uint32_t i = 0; i < num_vars - 1 - offset; ++i ) + { + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best_tt = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size + offset ); + } + + for ( uint32_t j = offset + 2; j < num_vars - i; ++j ) + { + std::swap( perm[offset + 1], perm[j] ); + kitty::swap_inplace( tt, offset + 1, j ); + + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best_tt = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size + offset ); + } + } + + std::swap( perm[offset], perm[num_vars - i - 1] ); + kitty::swap_inplace( tt, offset, num_vars - i - 1 ); + } + } + else if ( free_set_size == 3 ) + { + for ( uint32_t i = 0; i < num_vars - 2 - offset; ++i ) + { + for ( uint32_t j = i; j < num_vars - 2 - offset; ++j ) + { + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best_tt = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size + offset ); + } + + for ( uint32_t k = offset + 3; k < num_vars - j; ++k ) + { + std::swap( perm[offset + 2], perm[k] ); + kitty::swap_inplace( tt, offset + 2, k ); + + uint32_t cost = fn( tt ); + if ( cost < best_cost ) + { + best_tt = tt; + best_cost = cost; + best_perm = perm; + } + + if ( verbose ) + { + kitty::print_hex( tt ); + std::cout << " " << cost << " "; + print_perm( perm.begin(), free_set_size + offset ); + } + } + + std::swap( perm[offset + 1], perm[num_vars - j - 1] ); + kitty::swap_inplace( tt, offset + 1, num_vars - j - 1 ); + } + + std::swap( perm[offset], perm[num_vars - i - 1] ); + kitty::swap_inplace( tt, offset, num_vars - i - 1 ); + } + } + + std::vector res_perm( num_vars ); + std::copy( best_perm.begin(), best_perm.begin() + num_vars, res_perm.begin() ); + + return std::make_tuple( best_tt, res_perm, best_cost ); + } + + std::vector compute_isets( uint32_t free_set_size, bool verbose = false ) + { + /* construct isets involved in multiplicity */ + uint32_t isets_support = num_vars - free_set_size; + std::vector isets( best_multiplicity ); + + /* construct isets */ + std::unordered_map column_to_iset; + STT tt = best_tt; + uint32_t offset = 0; + uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + + if ( free_set_size == 1 ) + { + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < 32; ++j ) + { + uint64_t val = *it & 0x3; + + if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) + { + isets[el->second]._bits[i / 2] |= UINT64_C( 1 ) << ( j + offset ); + } + else + { + isets[column_to_iset.size()]._bits[i / 2] |= UINT64_C( 1 ) << ( j + offset ); + column_to_iset[val] = column_to_iset.size(); + } + + *it >>= 2; + } + + offset ^= 32; + ++it; + } + } + else if ( free_set_size == 2 ) + { + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < 16; ++j ) + { + uint64_t val = *it & 0xF; + + if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) + { + isets[el->second]._bits[i / 4] |= UINT64_C( 1 ) << ( j + offset ); + } + else + { + isets[column_to_iset.size()]._bits[i / 4] |= UINT64_C( 1 ) << ( j + offset ); + column_to_iset[val] = column_to_iset.size(); + } + + *it >>= 4; + } + + offset = ( offset + 16 ) % 64; + ++it; + } + } + else /* free set size 3 */ + { + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < 8; ++j ) + { + uint64_t val = *it & 0xFF; + + if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) + { + isets[el->second]._bits[i / 8] |= UINT64_C( 1 ) << ( j + offset ); + } + else + { + isets[column_to_iset.size()]._bits[i / 8] |= UINT64_C( 1 ) << ( j + offset ); + column_to_iset[val] = column_to_iset.size(); + } + + *it >>= 8; + } + + offset = ( offset + 8 ) % 64; + ++it; + } + } + + /* extend isets to cover the whole truth table */ + for ( STT& iset : isets ) + { + local_extend_to( iset, isets_support ); + } + + /* save free_set functions */ + std::vector free_set_tts( best_multiplicity ); + + /* TODO: possible conflict */ + for ( auto const& pair : column_to_iset ) + { + free_set_tts[pair.second]._bits[0] = pair.first; + local_extend_to( free_set_tts[pair.second], free_set_size ); + } + + /* print isets and free set*/ + if ( verbose ) + { + std::cout << "iSets\n"; + uint32_t i = 0; + for ( auto iset : isets ) + { + kitty::print_hex( iset ); + std::cout << " of func "; + kitty::print_hex( free_set_tts[i++] ); + std::cout << "\n"; + } + } + + best_free_set_tts = std::move( free_set_tts ); + + return isets; + } + + std::vector generate_decomposition( uint32_t free_set_size ) + { + std::vector res; + + for ( uint32_t i = 0; i < best_bound_sets.size(); ++i ) + { + ac_decomposition_result dec; + auto tt = best_bound_sets[i]; + auto care = best_care_sets[i]; + + /* compute and minimize support for bound set variables */ + uint32_t k = 0; + for ( uint32_t j = 0; j < num_vars - free_set_size; ++j ) + { + if ( !kitty::has_var( tt, j ) ) + continue; + + if ( !kitty::has_var( tt, care, j ) ) + { + /* fix truth table */ + adjust_truth_table_on_dc( tt, care, j ); + continue; + } + + if ( k < j ) + { + kitty::swap_inplace( tt, k, j ); + kitty::swap_inplace( care, k, j ); + } + dec.support.push_back( permutations[free_set_size + j] ); + ++k; + } + + dec.tt = kitty::shrink_to( tt, dec.support.size() ); + res.push_back( dec ); + } + + /* compute the decomposition for the top-level LUT */ + compute_top_lut_decomposition( res, free_set_size ); + + return res; + } + + void compute_top_lut_decomposition( std::vector& res, uint32_t free_set_size ) + { + uint32_t top_vars = best_bound_sets.size() + free_set_size; + assert( top_vars <= ps.lut_size ); + + /* extend bound set functions with free_set_size LSB vars */ + kitty::dynamic_truth_table tt( top_vars ); + + /* compute support */ + res.emplace_back(); + for ( uint32_t i = 0; i < free_set_size; ++i ) + { + res.back().support.push_back( permutations[i] ); + } + + /* create functions for bound set */ + std::vector bound_set_vars; + auto res_it = res.begin(); + uint32_t offset = 0; + for ( uint32_t i = 0; i < best_bound_sets.size(); ++i ) + { + bound_set_vars.emplace_back( top_vars ); + kitty::create_nth_var( bound_set_vars[i], free_set_size + i ); + + /* add bound-set variables to the support, remove buffers */ + if ( res_it->support.size() == 1 ) + { + res.back().support.push_back( res_it->support.front() ); + /* it is a NOT */ + if ( ( res_it->tt._bits[0] & 1 ) == 1 ) + { + bound_set_vars[i] = ~bound_set_vars[i]; + } + res.erase( res_it ); + ++offset; + } + else + { + res.back().support.push_back( num_vars + i - offset ); + ++res_it; + } + } + + /* create composition function */ + for ( uint32_t i = 0; i < best_free_set_tts.size(); ++i ) + { + kitty::dynamic_truth_table free_set_tt = kitty::shrink_to( best_free_set_tts[i], top_vars ); + + /* find MUX assignments */ + for ( uint32_t j = 0; j < bound_set_vars.size(); ++j ) + { + /* AND with ONSET or OFFSET */ + if ( ( ( best_iset_onset[j] >> i ) & 1 ) ) + { + free_set_tt &= bound_set_vars[j]; + } + else if ( ( ( best_iset_offset[j] >> i ) & 1 ) ) + { + free_set_tt &= ~bound_set_vars[j]; + } + } + + tt |= free_set_tt; + } + + /* add top-level LUT to result */ + res.back().tt = tt; + } + + inline void reposition_late_arriving_variables( unsigned delay_profile, uint32_t late_arriving ) + { + uint32_t k = 0; + for ( uint32_t i = 0; i < late_arriving; ++i ) + { + while ( ( ( delay_profile >> k ) & 1 ) == 0 ) + ++k; + + if ( permutations[i] == k ) + { + ++k; + continue; + } + + std::swap( permutations[i], permutations[k] ); + kitty::swap_inplace( best_tt, i, k ); + ++k; + } + } + + template + void print_perm( Iterator begin, uint32_t free_set ) + { + std::cout << "["; + for ( uint32_t i = 0; i < num_vars; ++i ) + { + if ( i == free_set ) + { + std::cout << ", "; + } + std::cout << *begin << " "; + ++begin; + } + std::cout << "]\n"; + } + + void generate_support_minimization_encodings() + { + uint32_t count = 0; + uint32_t num_combs_exact[4] = { 2, 6, 70, 12870 }; + + /* enable don't cares only if not a power of 2 */ + uint32_t num_combs = 3; + if ( __builtin_popcount( best_multiplicity ) == 1 ) + { + for ( uint32_t i = 0; i < 4; ++i ) + { + if ( ( best_multiplicity >> i ) == 2u ) + { + num_combs = num_combs_exact[i]; + } + } + support_minimization_encodings = std::vector>( num_combs ); + generate_support_minimization_encodings_rec( 0, 0, 0, count ); + } + else + { + for ( uint32_t i = 1; i < best_multiplicity; ++i ) + { + num_combs = ( num_combs << 1 ) + num_combs; + } + support_minimization_encodings = std::vector>( num_combs ); + generate_support_minimization_encodings_rec( 0, 0, 0, count ); + } + + assert( count == num_combs ); + + /* print combinations */ + // std::cout << "{ "; + // for ( auto const& entry : support_minimization_encodings ) + // { + // std::cout << "{ " << entry[0] << ", " << entry[1] << " }, "; + // } + // std::cout << "}\n"; + } + + template + void generate_support_minimization_encodings_rec( uint64_t onset, uint64_t offset, uint32_t var, uint32_t& count ) + { + if ( var == best_multiplicity ) + { + if constexpr ( !enable_dcset ) + { + /* sets must be equally populated */ + if ( __builtin_popcountl( onset ) != __builtin_popcountl( offset ) ) + { + return; + } + } + + support_minimization_encodings[count][0] = onset; + support_minimization_encodings[count][1] = offset; + ++count; + return; + } + + /* move var in DCSET */ + if constexpr ( enable_dcset ) + { + generate_support_minimization_encodings_rec( onset, offset, var + 1, count ); + } + + /* move var in ONSET */ + onset |= 1 << var; + generate_support_minimization_encodings_rec( onset, offset, var + 1, count ); + onset &= ~( 1 << var ); + + /* move var in OFFSET */ + offset |= 1 << var; + generate_support_minimization_encodings_rec( onset, offset, var + 1, count ); + offset &= ~( 1 << var ); + } + + void solve_min_support_exact( std::vector const& isets, uint32_t free_set_size ) + { + std::vector matrix; + matrix.reserve( support_minimization_encodings.size() ); + best_bound_sets.clear(); + + /* create covering matrix */ + if ( !create_covering_matrix( isets, matrix, free_set_size, best_multiplicity > 4 ) ) + { + return; + } + + /* solve the covering problem */ + std::array solution = covering_solve_exact( matrix, 100, ps.max_iter ); + + /* check for failed decomposition */ + if ( solution[0] == UINT32_MAX ) + { + return; + } + + /* compute best bound sets */ + uint32_t num_luts = 1 + solution[4]; + uint32_t num_levels = 2; + uint32_t num_edges = free_set_size + solution[4]; + uint32_t isets_support = num_vars - free_set_size; + best_care_sets.clear(); + best_iset_onset.clear(); + best_iset_offset.clear(); + for ( uint32_t i = 0; i < solution[4]; ++i ) + { + STT tt; + STT care; + + const uint32_t onset = support_minimization_encodings[matrix[solution[i]].index][0]; + const uint32_t offset = support_minimization_encodings[matrix[solution[i]].index][1]; + for ( uint32_t j = 0; j < best_multiplicity; ++j ) + { + if ( ( ( onset >> j ) & 1 ) ) + { + tt |= isets[j]; + } + if ( ( ( offset >> j ) & 1 ) ) + { + care |= isets[j]; + } + } + + care |= tt; + num_edges += matrix[solution[i]].cost & ( ( 1 << isets_support ) - 1 ); + + best_bound_sets.push_back( tt ); + best_care_sets.push_back( care ); + best_iset_onset.push_back( onset ); + best_iset_offset.push_back( offset ); + } + + if ( pst != nullptr ) + { + pst->num_luts = num_luts; + pst->num_levels = num_levels; + pst->num_edges = num_edges; + } + } + + bool create_covering_matrix( std::vector const& isets, std::vector& matrix, uint32_t free_set_size, bool sort ) + { + assert( best_multiplicity < 12 ); + uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; + uint64_t sol_existance = 0; + uint32_t iset_support = num_vars - free_set_size; + + /* insert dichotomies */ + for ( uint32_t i = 0; i < support_minimization_encodings.size(); ++i ) + { + uint32_t const onset = support_minimization_encodings[i][0]; + uint32_t const offset = support_minimization_encodings[i][1]; + + uint32_t ones_onset = __builtin_popcount( onset ); + uint32_t ones_offset = __builtin_popcount( offset ); + + /* filter columns that do not distinguish pairs */ + if ( ones_onset == 0 || ones_offset == 0 || ones_onset == best_multiplicity || ones_offset == best_multiplicity ) + { + continue; + } + + /* compute function and distinguishable seed dichotomies */ + uint64_t column = 0; + STT tt; + STT care; + uint32_t pair_pointer = 0; + for ( uint32_t j = 0; j < best_multiplicity; ++j ) + { + auto onset_shift = ( onset >> j ); + auto offset_shift = ( offset >> j ); + if ( ( onset_shift & 1 ) ) + { + tt |= isets[j]; + } + + if ( ( offset_shift & 1 ) ) + { + care |= isets[j]; + } + + /* compute included seed dichotomies */ + for ( uint32_t k = j + 1; k < best_multiplicity; ++k ) + { + /* if is are in diffent sets */ + if ( ( ( ( onset_shift & ( offset >> k ) ) | ( ( onset >> k ) & offset_shift ) ) & 1 ) ) + { + column |= UINT64_C( 1 ) << ( pair_pointer ); + } + + ++pair_pointer; + } + } + + care |= tt; + + /* compute cost */ + uint32_t cost = 0; + for ( uint32_t j = 0; j < iset_support; ++j ) + { + cost += has_var_support( tt, care, iset_support, j ) ? 1 : 0; + } + + /* discard solutions with support over LUT size */ + if ( cost > ps.lut_size ) + continue; + + if ( cost > 1 ) + { + cost |= 1 << iset_support; + } + + uint32_t sort_cost = cost + ( ( combinations - __builtin_popcountl( column ) ) << num_vars ); + + /* insert */ + matrix.emplace_back( encoding_matrix{ column, cost, i, sort_cost } ); + + sol_existance |= column; + } + + /* necessary condition for the existance of a solution */ + if ( __builtin_popcountl( sol_existance ) != combinations ) + { + return false; + } + + if ( !sort ) + { + return true; + } + + std::sort( matrix.begin(), matrix.end(), [&]( auto const& a, auto const& b ) { + return a.sort_cost < b.sort_cost; + } ); + + /* print */ + // if ( best_multiplicity < 6 ) + // { + // for ( uint32_t i = 0; i < columns.size(); ++i ) + // { + // std::cout << indexes[i] << " " << costs[i] << " \t" << columns[i] << "\n"; + // } + // } + + return true; + } + + template + std::array covering_solve_exact( std::vector& matrix, uint32_t max_iter = 100, int32_t limit = 2000 ) + { + /* last value of res contains the size of the bound set */ + std::array res = { UINT32_MAX }; + uint32_t best_cost = UINT32_MAX; + uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; + bool looping = true; + + assert( best_multiplicity <= 16 ); + + /* determine the number of needed loops*/ + if ( best_multiplicity <= 4 ) + { + res[4] = 2; + for ( uint32_t i = 0; i < matrix.size() - 1; ++i ) + { + for ( uint32_t j = 1; j < matrix.size(); ++j ) + { + /* filter by cost */ + if ( matrix[i].cost + matrix[j].cost >= best_cost ) + continue; + + /* check validity */ + if ( __builtin_popcountl( matrix[i].column | matrix[j].column ) == combinations ) + { + res[0] = i; + res[1] = j; + best_cost = matrix[i].cost + matrix[j].cost; + } + } + } + } + else if ( best_multiplicity <= 8 ) + { + res[4] = 3; + for ( uint32_t i = 0; i < matrix.size() - 2 && looping; ++i ) + { + /* limit */ + if constexpr ( limit_iter ) + { + if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + { + looping = false; + } + } + + for ( uint32_t j = 1; j < matrix.size() - 1 && looping; ++j ) + { + uint64_t current_columns = matrix[i].column | matrix[j].column; + uint32_t current_cost = matrix[i].cost + matrix[j].cost; + + /* limit */ + if constexpr ( limit_iter ) + { + if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + { + looping = false; + } + } + + /* bound */ + if ( current_cost >= best_cost ) + { + continue; + } + + for ( uint32_t k = 2; k < matrix.size() && looping; ++k ) + { + /* limit */ + if constexpr ( limit_iter ) + { + if ( limit-- <= 0 || ( best_cost < UINT32_MAX && max_iter-- == 0 ) ) + { + looping = false; + } + } + + /* filter by cost */ + if ( current_cost + matrix[k].cost >= best_cost ) + continue; + + /* check validity */ + if ( __builtin_popcountl( current_columns | matrix[k].column ) == combinations ) + { + res[0] = i; + res[1] = j; + res[2] = k; + best_cost = current_cost + matrix[k].cost; + } + } + } + } + } + else + { + res[4] = 4; + for ( uint32_t i = 0; i < matrix.size() - 3 && looping; ++i ) + { + /* limit */ + if constexpr ( limit_iter ) + { + if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + { + looping = false; + } + } + + for ( uint32_t j = 1; j < matrix.size() - 2 && looping; ++j ) + { + uint64_t current_columns0 = matrix[i].column | matrix[j].column; + uint32_t current_cost0 = matrix[i].cost + matrix[j].cost; + + /* limit */ + if constexpr ( limit_iter ) + { + if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + { + looping = false; + } + } + + /* bound */ + if ( current_cost0 >= best_cost ) + { + continue; + } + + for ( uint32_t k = 2; k < matrix.size() - 1 && looping; ++k ) + { + uint64_t current_columns1 = current_columns0 | matrix[k].column; + uint32_t current_cost1 = current_cost0 + matrix[k].cost; + + /* limit */ + if constexpr ( limit_iter ) + { + if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + { + looping = false; + } + } + + /* bound */ + if ( current_cost1 >= best_cost ) + { + continue; + } + + for ( uint32_t t = 3; t < matrix.size() && looping; ++t ) + { + /* limit */ + if constexpr ( limit_iter ) + { + if ( limit-- <= 0 || ( best_cost < UINT32_MAX && max_iter-- == 0 ) ) + { + looping = false; + } + } + + /* filter by cost */ + if ( current_cost1 + matrix[t].cost >= best_cost ) + continue; + + /* check validity */ + if ( __builtin_popcountl( current_columns1 | matrix[t].column ) == combinations ) + { + res[0] = i; + res[1] = j; + res[2] = k; + res[3] = t; + best_cost = current_cost1 + matrix[t].cost; + } + } + } + } + } + } + + return res; + } + + void adjust_truth_table_on_dc( STT& tt, STT& care, uint32_t var_index ) + { + assert( var_index < tt.num_vars() ); + assert( tt.num_vars() == care.num_vars() ); + + if ( tt.num_vars() <= 6 || var_index < 6 ) + { + auto it_tt = std::begin( tt._bits ); + auto it_care = std::begin( care._bits ); + while ( it_tt != std::end( tt._bits ) ) + { + uint64_t new_bits = *it_tt & *it_care; + *it_tt = ( ( new_bits | ( new_bits >> ( uint64_t( 1 ) << var_index ) ) ) & kitty::detail::projections_neg[var_index] ) | + ( ( new_bits | ( new_bits << ( uint64_t( 1 ) << var_index ) ) ) & kitty::detail::projections[var_index] ); + *it_care = *it_care | ( *it_care >> ( uint64_t( 1 ) << var_index ) ); + + ++it_tt; + ++it_care; + } + return; + } + + const auto step = 1 << ( var_index - 6 ); + for ( auto i = 0u; i < static_cast( tt.num_blocks() ); i += 2 * step ) + { + for ( auto j = 0; j < step; ++j ) + { + tt._bits[i + j] = ( tt._bits[i + j] & care._bits[i + j] ) | ( tt._bits[i + j + step] & care._bits[i + j + step] ); + tt._bits[i + j + step] = tt._bits[i + j]; + care._bits[i + j] = care._bits[i + j] | care._bits[i + j + step]; + care._bits[i + j + step] = care._bits[i + j]; + } + } + } + + void local_extend_to( STT& tt, uint32_t real_num_vars ) + { + if ( real_num_vars < 6 ) + { + auto mask = *tt.begin(); + + for ( auto i = real_num_vars; i < num_vars; ++i ) + { + mask |= ( mask << ( 1 << i ) ); + } + + std::fill( tt.begin(), tt.end(), mask ); + } + else + { + uint32_t num_blocks = ( 1u << ( real_num_vars - 6 ) ); + auto it = tt.begin(); + while ( it != tt.end() ) + { + it = std::copy( tt.cbegin(), tt.cbegin() + num_blocks, it ); + } + } + } + + bool has_var_support( const STT& tt, const STT& care, uint32_t real_num_vars, uint8_t var_index ) + { + assert( var_index < real_num_vars ); + assert( real_num_vars <= tt.num_vars() ); + assert( tt.num_vars() == care.num_vars() ); + + const uint32_t num_blocks = real_num_vars <= 6 ? 1 : ( 1 << ( real_num_vars - 6 ) ); + if ( real_num_vars <= 6 || var_index < 6 ) + { + auto it_tt = std::begin( tt._bits ); + auto it_care = std::begin( care._bits ); + while ( it_tt != std::begin( tt._bits ) + num_blocks ) + { + if ( ( ( ( *it_tt >> ( uint64_t( 1 ) << var_index ) ) ^ *it_tt ) & kitty::detail::projections_neg[var_index] + & ( *it_care >> ( uint64_t( 1 ) << var_index ) ) & *it_care ) != 0 ) + { + return true; + } + ++it_tt; + ++it_care; + } + + return false; + } + + const auto step = 1 << ( var_index - 6 ); + for ( auto i = 0u; i < num_blocks; i += 2 * step ) + { + for ( auto j = 0; j < step; ++j ) + { + if ( ( ( tt._bits[i + j] ^ tt._bits[i + j + step] ) & care._bits[i + j] & care._bits[i + j + step] ) != 0 ) + { + return true; + } + } + } + + return false; + } + + void get_decomposition_abc( unsigned char *decompArray ) + { + unsigned char *pArray = decompArray; + unsigned char bytes = 2; + + /* write number of LUTs */ + pArray++; + *pArray = dec_result.size(); + pArray++; + + /* write LUTs */ + for ( ac_decomposition_result const& lut : dec_result ) + { + /* write fanin size*/ + *pArray = lut.support.size(); + pArray++; ++bytes; + + /* write support */ + for ( uint32_t i : lut.support ) + { + *pArray = (unsigned char) i; + pArray++; ++bytes; + } + + /* write truth table */ + uint32_t tt_num_bytes = ( lut.tt.num_vars() <= 3 ) ? 1 : ( 1 << ( lut.tt.num_vars() - 3 ) ); + tt_num_bytes = std::min( tt_num_bytes, 8u ); + for ( uint32_t i = 0; i < lut.tt.num_blocks(); ++i ) + { + for ( uint32_t j = 0; j < tt_num_bytes; ++j ) + { + *pArray = (unsigned char) ( ( lut.tt._bits[i] >> ( 8 * j ) ) & 0xFF ); + pArray++; ++bytes; + } + } + } + + /* write numBytes */ + *decompArray = bytes; + } + +private: + uint32_t best_multiplicity{ UINT32_MAX }; + uint32_t best_free_set{ UINT32_MAX }; + STT best_tt; + std::vector best_bound_sets; + std::vector best_care_sets; + std::vector best_free_set_tts; + std::vector best_iset_onset; + std::vector best_iset_offset; + std::vector dec_result; + + std::vector> support_minimization_encodings; + + TT tt_start; + uint32_t num_vars; + ac_decomposition_params const& ps; + ac_decomposition_stats* pst; + std::vector permutations; +}; + +} // namespace mockturtle + +#endif // _ACD_H_ \ No newline at end of file diff --git a/src/acd/ac_wrapper.cpp b/src/acd/ac_wrapper.cpp new file mode 100644 index 0000000000..b7cee0dd75 --- /dev/null +++ b/src/acd/ac_wrapper.cpp @@ -0,0 +1,69 @@ +// #include "base/main/main.h" +#include "ac_wrapper.h" +#include "ac_decomposition.hpp" + +// ABC_NAMESPACE_IMPL_START + +int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost ) +{ + using namespace mockturtle; + + int num_blocks = ( nVars <= 6 ) ? 1 : ( 1 << ( nVars - 6 ) ); + + /* translate truth table into static table */ + kitty::dynamic_truth_table tt( nVars ); + for ( int i = 0; i < num_blocks; ++i ) + tt._bits[i] = pTruth[i]; + + ac_decomposition_params ps; + ps.lut_size = lutSize; + ac_decomposition_stats st; + + ac_decomposition_impl acd( tt, nVars, ps, &st ); + acd.run( *pdelay ); + int val = acd.compute_decomposition(); + + if ( val < 0 ) + { + *pdelay = 0; + return -1; + } + + *pdelay = acd.get_profile(); + *cost = st.num_luts; + + return 0; +} + +int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ) +{ + using namespace mockturtle; + + int num_blocks = ( nVars <= 6 ) ? 1 : ( 1 << ( nVars - 6 ) ); + + /* translate truth table into static table */ + kitty::dynamic_truth_table tt( nVars ); + for ( int i = 0; i < num_blocks; ++i ) + tt._bits[i] = pTruth[i]; + + ac_decomposition_params ps; + ps.lut_size = lutSize; + ac_decomposition_stats st; + + ac_decomposition_impl acd( tt, nVars, ps, &st ); + acd.run( *pdelay ); + int val = acd.compute_decomposition(); + + if ( val < 0 ) + { + *pdelay = 0; + return -1; + } + + *pdelay = acd.get_profile(); + + acd.get_decomposition( decomposition ); + return 0; +} + +// ABC_NAMESPACE_IMPL_END \ No newline at end of file diff --git a/src/acd/ac_wrapper.h b/src/acd/ac_wrapper.h new file mode 100644 index 0000000000..522a60b865 --- /dev/null +++ b/src/acd/ac_wrapper.h @@ -0,0 +1,23 @@ +// #pragma once +#ifndef __ACD_WRAPPER_H_ +#define __ACD_WRAPPER_H_ + +// #include "base/main/main.h" +#include "misc/util/abc_global.h" + +// ABC_NAMESPACE_HEADER_START + +#ifdef __cplusplus +extern "C" { +#endif + +int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost ); +int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ); + +#ifdef __cplusplus +} +#endif + +// ABC_NAMESPACE_HEADER_END + +#endif \ No newline at end of file diff --git a/src/acd/kitty_algorithm.hpp b/src/acd/kitty_algorithm.hpp new file mode 100644 index 0000000000..6460a802cf --- /dev/null +++ b/src/acd/kitty_algorithm.hpp @@ -0,0 +1,119 @@ +#ifndef _KITTY_ALGORITHM_H_ +#define _KITTY_ALGORITHM_H_ +#pragma once + +#include +#include + +#include "kitty_constants.hpp" +#include "kitty_dynamic_tt.hpp" +#include "kitty_static_tt.hpp" + +namespace kitty +{ + +/*! \brief Perform bitwise unary operation on truth table + + \param tt Truth table + \param op Unary operation that takes as input a word (`uint64_t`) and returns a word + + \return new constructed truth table of same type and dimensions + */ +template +auto unary_operation( const TT& tt, Fn&& op ) +{ + auto result = tt.construct(); + std::transform( tt.cbegin(), tt.cend(), result.begin(), op ); + result.mask_bits(); + return result; +} + +/*! \brief Perform bitwise binary operation on two truth tables + + The dimensions of `first` and `second` must match. This is ensured + at compile-time for static truth tables, but at run-time for dynamic + truth tables. + + \param first First truth table + \param second Second truth table + \param op Binary operation that takes as input two words (`uint64_t`) and returns a word + + \return new constructed truth table of same type and dimensions + */ +template +auto binary_operation( const TT& first, const TT& second, Fn&& op ) +{ + assert( first.num_vars() == second.num_vars() ); + + auto result = first.construct(); + std::transform( first.cbegin(), first.cend(), second.cbegin(), result.begin(), op ); + result.mask_bits(); + return result; +} + +/*! \brief Computes a predicate based on two truth tables + + The dimensions of `first` and `second` must match. This is ensured + at compile-time for static truth tables, but at run-time for dynamic + truth tables. + + \param first First truth table + \param second Second truth table + \param op Binary operation that takes as input two words (`uint64_t`) and returns a Boolean + + \return true or false based on the predicate + */ +template +bool binary_predicate( const TT& first, const TT& second, Fn&& op ) +{ + assert( first.num_vars() == second.num_vars() ); + + return std::equal( first.begin(), first.end(), second.begin(), op ); +} + +/*! \brief Assign computed values to bits + + The functor `op` computes bits which are assigned to the bits of the + truth table. + + \param tt Truth table + \param op Unary operation that takes no input and returns a word (`uint64_t`) +*/ +template +void assign_operation( TT& tt, Fn&& op ) +{ + std::generate( tt.begin(), tt.end(), op ); + tt.mask_bits(); +} + +/*! \brief Iterates through each block of a truth table + + The functor `op` is called for every block of the truth table. + + \param tt Truth table + \param op Unary operation that takes as input a word (`uint64_t`) and returns void +*/ +template +void for_each_block( const TT& tt, Fn&& op ) +{ + std::for_each( tt.cbegin(), tt.cend(), op ); +} + +/*! \brief Iterates through each block of a truth table in reverse + order + + The functor `op` is called for every block of the truth table in + reverse order. + + \param tt Truth table + \param op Unary operation that takes as input a word (`uint64_t`) and returns void +*/ +template +void for_each_block_reversed( const TT& tt, Fn&& op ) +{ + std::for_each( tt.crbegin(), tt.crend(), op ); +} + +} // namespace kitty + +#endif // _KITTY_ALGORITHM_H_ \ No newline at end of file diff --git a/src/acd/kitty_constants.hpp b/src/acd/kitty_constants.hpp new file mode 100644 index 0000000000..55cfcd650f --- /dev/null +++ b/src/acd/kitty_constants.hpp @@ -0,0 +1,91 @@ +#ifndef _KITTY_CONSTANTS_H_ +#define _KITTY_CONSTANTS_H_ +#pragma once + +#include +#include + +namespace kitty +{ + +namespace detail +{ + +static constexpr uint64_t projections[] = { + UINT64_C( 0xaaaaaaaaaaaaaaaa ), + UINT64_C( 0xcccccccccccccccc ), + UINT64_C( 0xf0f0f0f0f0f0f0f0 ), + UINT64_C( 0xff00ff00ff00ff00 ), + UINT64_C( 0xffff0000ffff0000 ), + UINT64_C( 0xffffffff00000000 ) }; + +static constexpr uint64_t projections_neg[] = { + UINT64_C( 0x5555555555555555 ), + UINT64_C( 0x3333333333333333 ), + UINT64_C( 0x0f0f0f0f0f0f0f0f ), + UINT64_C( 0x00ff00ff00ff00ff ), + UINT64_C( 0x0000ffff0000ffff ), + UINT64_C( 0x00000000ffffffff ) }; + +static constexpr uint64_t masks[] = { + UINT64_C( 0x0000000000000001 ), + UINT64_C( 0x0000000000000003 ), + UINT64_C( 0x000000000000000f ), + UINT64_C( 0x00000000000000ff ), + UINT64_C( 0x000000000000ffff ), + UINT64_C( 0x00000000ffffffff ), + UINT64_C( 0xffffffffffffffff ) }; + +static constexpr uint64_t permutation_masks[][3] = { + { UINT64_C( 0x9999999999999999 ), UINT64_C( 0x2222222222222222 ), UINT64_C( 0x4444444444444444 ) }, + { UINT64_C( 0xc3c3c3c3c3c3c3c3 ), UINT64_C( 0x0c0c0c0c0c0c0c0c ), UINT64_C( 0x3030303030303030 ) }, + { UINT64_C( 0xf00ff00ff00ff00f ), UINT64_C( 0x00f000f000f000f0 ), UINT64_C( 0x0f000f000f000f00 ) }, + { UINT64_C( 0xff0000ffff0000ff ), UINT64_C( 0x0000ff000000ff00 ), UINT64_C( 0x00ff000000ff0000 ) }, + { UINT64_C( 0xffff00000000ffff ), UINT64_C( 0x00000000ffff0000 ), UINT64_C( 0x0000ffff00000000 ) } }; + +static constexpr uint64_t ppermutation_masks[][6][3] = { + { { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x9999999999999999 ), UINT64_C( 0x2222222222222222 ), UINT64_C( 0x4444444444444444 ) }, + { UINT64_C( 0xa5a5a5a5a5a5a5a5 ), UINT64_C( 0x0a0a0a0a0a0a0a0a ), UINT64_C( 0x5050505050505050 ) }, + { UINT64_C( 0xaa55aa55aa55aa55 ), UINT64_C( 0x00aa00aa00aa00aa ), UINT64_C( 0x5500550055005500 ) }, + { UINT64_C( 0xaaaa5555aaaa5555 ), UINT64_C( 0x0000aaaa0000aaaa ), UINT64_C( 0x5555000055550000 ) }, + { UINT64_C( 0xaaaaaaaa55555555 ), UINT64_C( 0x00000000aaaaaaaa ), UINT64_C( 0x5555555500000000 ) } }, + { { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0xc3c3c3c3c3c3c3c3 ), UINT64_C( 0x0c0c0c0c0c0c0c0c ), UINT64_C( 0x3030303030303030 ) }, + { UINT64_C( 0xcc33cc33cc33cc33 ), UINT64_C( 0x00cc00cc00cc00cc ), UINT64_C( 0x3300330033003300 ) }, + { UINT64_C( 0xcccc3333cccc3333 ), UINT64_C( 0x0000cccc0000cccc ), UINT64_C( 0x3333000033330000 ) }, + { UINT64_C( 0xcccccccc33333333 ), UINT64_C( 0x00000000cccccccc ), UINT64_C( 0x3333333300000000 ) } }, + { { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0xf00ff00ff00ff00f ), UINT64_C( 0x00f000f000f000f0 ), UINT64_C( 0x0f000f000f000f00 ) }, + { UINT64_C( 0xf0f00f0ff0f00f0f ), UINT64_C( 0x0000f0f00000f0f0 ), UINT64_C( 0x0f0f00000f0f0000 ) }, + { UINT64_C( 0xf0f0f0f00f0f0f0f ), UINT64_C( 0x00000000f0f0f0f0 ), UINT64_C( 0x0f0f0f0f00000000 ) } }, + { { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0xff0000ffff0000ff ), UINT64_C( 0x0000ff000000ff00 ), UINT64_C( 0x00ff000000ff0000 ) }, + { UINT64_C( 0xff00ff0000ff00ff ), UINT64_C( 0x00000000ff00ff00 ), UINT64_C( 0x00ff00ff00000000 ) } }, + { { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ), UINT64_C( 0x0000000000000000 ) }, + { UINT64_C( 0xffff00000000ffff ), UINT64_C( 0x00000000ffff0000 ), UINT64_C( 0x0000ffff00000000 ) } } }; + +static constexpr int32_t hex_to_int[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + +} // namespace detail + +} // namespace kitty + +#endif //_KITTY_CONSTANTS_H_ \ No newline at end of file diff --git a/src/acd/kitty_constructors.hpp b/src/acd/kitty_constructors.hpp new file mode 100644 index 0000000000..43408b8cc3 --- /dev/null +++ b/src/acd/kitty_constructors.hpp @@ -0,0 +1,92 @@ +#ifndef _KITTY_CONSTRUCT_TT_H_ +#define _KITTY_CONSTRUCT_TT_H_ +#pragma once + +#include +#include +#include +#include +#include + +#include "kitty_constants.hpp" +#include "kitty_dynamic_tt.hpp" +#include "kitty_static_tt.hpp" + +namespace kitty +{ + +/*! \brief Creates truth table with number of variables + + If some truth table instance is given, one can create a truth table with the + same type by calling the `construct()` method on it. This function helps if + only the number of variables is known and the base type and uniforms the + creation of static and dynamic truth tables. Note, however, that for static + truth tables `num_vars` must be consistent to the number of variables in the + truth table type. + + \param num_vars Number of variables +*/ +template +inline TT create( unsigned num_vars ) +{ + (void)num_vars; + TT tt; + assert( tt.num_vars() == num_vars ); + return tt; +} + +/*! \cond PRIVATE */ +template<> +inline dynamic_truth_table create( unsigned num_vars ) +{ + return dynamic_truth_table( num_vars ); +} +/*! \endcond */ + +/*! \brief Constructs projections (single-variable functions) + + \param tt Truth table + \param var_index Index of the variable, must be smaller than the truth table's number of variables + \param complement If true, realize inverse projection +*/ +template +void create_nth_var( TT& tt, uint8_t var_index, bool complement = false ) +{ + if ( tt.num_vars() <= 6 ) + { + /* assign from precomputed table */ + tt._bits[0] = complement ? ~detail::projections[var_index] : detail::projections[var_index]; + + /* mask if truth table does not require all bits */ + tt.mask_bits(); + return; + } + + if ( var_index < 6 ) + { + std::fill( std::begin( tt._bits ), std::end( tt._bits ), complement ? ~detail::projections[var_index] : detail::projections[var_index] ); + } + else + { + const auto c = 1 << ( var_index - 6 ); + const auto zero = uint64_t( 0 ); + const auto one = ~zero; + auto block = uint64_t( 0u ); + + while ( block < tt.num_blocks() ) + { + for ( auto i = 0; i < c; ++i ) + { + tt._bits[block++] = complement ? one : zero; + } + for ( auto i = 0; i < c; ++i ) + { + tt._bits[block++] = complement ? zero : one; + } + } + } +} + +} // namespace kitty + +#endif // _KITTY_CONSTRUCT_TT_H_ \ No newline at end of file diff --git a/src/acd/kitty_dynamic_tt.hpp b/src/acd/kitty_dynamic_tt.hpp new file mode 100644 index 0000000000..f3ef0c7d9a --- /dev/null +++ b/src/acd/kitty_dynamic_tt.hpp @@ -0,0 +1,147 @@ +#ifndef _KITTY_DYNAMIC_TT_H_ +#define _KITTY_DYNAMIC_TT_H_ +#pragma once + +#include +#include +#include + +#include "kitty_constants.hpp" + +namespace kitty +{ + +/*! Truth table in which number of variables is known at runtime. + */ +struct dynamic_truth_table +{ + /*! Standard constructor. + + The number of variables provided to the truth table can be + computed at runtime. However, once the truth table is constructed + its number of variables cannot change anymore. + + The constructor computes the number of blocks and resizes the + vector accordingly. + + \param num_vars Number of variables + */ + explicit dynamic_truth_table( uint32_t num_vars ) + : _bits( ( num_vars <= 6 ) ? 1u : ( 1u << ( num_vars - 6 ) ) ), + _num_vars( num_vars ) + { + } + + /*! Empty constructor. + + Creates an empty truth table. It has 0 variables, but no bits, i.e., it is + different from a truth table for the constant function. This constructor is + only used for convenience, if algorithms require the existence of default + constructable classes. + */ + dynamic_truth_table() : _num_vars( 0 ) {} + + /*! Constructs a new dynamic truth table instance with the same number of variables. */ + inline dynamic_truth_table construct() const + { + return dynamic_truth_table( _num_vars ); + } + + /*! Returns number of variables. + */ + inline auto num_vars() const noexcept { return _num_vars; } + + /*! Returns number of blocks. + */ + inline auto num_blocks() const noexcept { return _bits.size(); } + + /*! Returns number of bits. + */ + inline auto num_bits() const noexcept { return uint64_t( 1 ) << _num_vars; } + + /*! \brief Begin iterator to bits. + */ + inline auto begin() noexcept { return _bits.begin(); } + + /*! \brief End iterator to bits. + */ + inline auto end() noexcept { return _bits.end(); } + + /*! \brief Begin iterator to bits. + */ + inline auto begin() const noexcept { return _bits.begin(); } + + /*! \brief End iterator to bits. + */ + inline auto end() const noexcept { return _bits.end(); } + + /*! \brief Reverse begin iterator to bits. + */ + inline auto rbegin() noexcept { return _bits.rbegin(); } + + /*! \brief Reverse end iterator to bits. + */ + inline auto rend() noexcept { return _bits.rend(); } + + /*! \brief Constant begin iterator to bits. + */ + inline auto cbegin() const noexcept { return _bits.cbegin(); } + + /*! \brief Constant end iterator to bits. + */ + inline auto cend() const noexcept { return _bits.cend(); } + + /*! \brief Constant reverse begin iterator to bits. + */ + inline auto crbegin() const noexcept { return _bits.crbegin(); } + + /*! \brief Constant teverse end iterator to bits. + */ + inline auto crend() const noexcept { return _bits.crend(); } + + /*! \brief Assign other truth table. + + This replaces the current truth table with another truth table. The truth + table type has to be complete. The vector of bits is resized accordingly. + + \param other Other truth table + */ + template + dynamic_truth_table& operator=( const TT& other ) + { + _bits.resize( other.num_blocks() ); + std::copy( other.begin(), other.end(), begin() ); + _num_vars = other.num_vars(); + + if ( _num_vars < 6 ) + { + mask_bits(); + } + + return *this; + } + + /*! Masks the number of valid truth table bits. + + If the truth table has less than 6 variables, it may not use all + the bits. This operation makes sure to zero out all non-valid + bits. + */ + inline void mask_bits() noexcept + { + if ( _num_vars < 6 ) + { + _bits[0u] &= detail::masks[_num_vars]; + } + } + + /*! \cond PRIVATE */ +public: /* fields */ + std::vector _bits; + uint32_t _num_vars; + /*! \endcond */ +}; + +} //namespace kitty + +#endif // _KITTY_DYNAMIC_TT_H_ \ No newline at end of file diff --git a/src/acd/kitty_operations.hpp b/src/acd/kitty_operations.hpp new file mode 100644 index 0000000000..fb504489a4 --- /dev/null +++ b/src/acd/kitty_operations.hpp @@ -0,0 +1,333 @@ +#ifndef _KITTY_OPERATIONS_TT_H_ +#define _KITTY_OPERATIONS_TT_H_ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "kitty_algorithm.hpp" +#include "kitty_constants.hpp" +#include "kitty_dynamic_tt.hpp" +#include "kitty_static_tt.hpp" + +namespace kitty +{ + +/*! Inverts all bits in a truth table, based on a condition */ +template +inline TT unary_not_if( const TT& tt, bool cond ) +{ +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + const auto mask = -static_cast( cond ); +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + return unary_operation( tt, [mask]( auto a ) + { return a ^ mask; } ); +} + +/*! \brief Inverts all bits in a truth table */ +template +inline TT unary_not( const TT& tt ) +{ + return unary_operation( tt, []( auto a ) + { return ~a; } ); +} + +/*! \brief Bitwise AND of two truth tables */ +template + +inline TT binary_and( const TT& first, const TT& second ) +{ + return binary_operation( first, second, std::bit_and<>() ); +} + +/*! \brief Bitwise OR of two truth tables */ +template +inline TT binary_or( const TT& first, const TT& second ) +{ + return binary_operation( first, second, std::bit_or<>() ); +} + +/*! \brief Swaps two variables in a truth table + + The function swaps variable `var_index1` with `var_index2`. The + function will change `tt` in-place. If `tt` should not be changed, + one can use `swap` instead. + + \param tt Truth table + \param var_index1 First variable + \param var_index2 Second variable +*/ +template +void swap_inplace( TT& tt, uint8_t var_index1, uint8_t var_index2 ) +{ + if ( var_index1 == var_index2 ) + { + return; + } + + if ( var_index1 > var_index2 ) + { + std::swap( var_index1, var_index2 ); + } + + if ( tt.num_vars() <= 6 ) + { + const auto& pmask = detail::ppermutation_masks[var_index1][var_index2]; + const auto shift = ( 1 << var_index2 ) - ( 1 << var_index1 ); + tt._bits[0] = ( tt._bits[0] & pmask[0] ) | ( ( tt._bits[0] & pmask[1] ) << shift ) | ( ( tt._bits[0] & pmask[2] ) >> shift ); + } + else if ( var_index2 <= 5 ) + { + const auto& pmask = detail::ppermutation_masks[var_index1][var_index2]; + const auto shift = ( 1 << var_index2 ) - ( 1 << var_index1 ); + std::transform( std::begin( tt._bits ), std::end( tt._bits ), std::begin( tt._bits ), + [shift, &pmask]( uint64_t word ) + { + return ( word & pmask[0] ) | ( ( word & pmask[1] ) << shift ) | ( ( word & pmask[2] ) >> shift ); + } ); + } + else if ( var_index1 <= 5 ) /* in this case, var_index2 > 5 */ + { + const auto step = 1 << ( var_index2 - 6 ); + const auto shift = 1 << var_index1; + auto it = std::begin( tt._bits ); + while ( it != std::end( tt._bits ) ) + { + for ( auto i = decltype( step ){ 0 }; i < step; ++i ) + { + const auto low_to_high = ( *( it + i ) & detail::projections[var_index1] ) >> shift; + const auto high_to_low = ( *( it + i + step ) << shift ) & detail::projections[var_index1]; + *( it + i ) = ( *( it + i ) & ~detail::projections[var_index1] ) | high_to_low; + *( it + i + step ) = ( *( it + i + step ) & detail::projections[var_index1] ) | low_to_high; + } + it += 2 * step; + } + } + else + { + const auto step1 = 1 << ( var_index1 - 6 ); + const auto step2 = 1 << ( var_index2 - 6 ); + auto it = std::begin( tt._bits ); + while ( it != std::end( tt._bits ) ) + { + for ( auto i = 0; i < step2; i += 2 * step1 ) + { + for ( auto j = 0; j < step1; ++j ) + { + std::swap( *( it + i + j + step1 ), *( it + i + j + step2 ) ); + } + } + it += 2 * step2; + } + } +} + +/*! \brief Extends smaller truth table to larger one + + The most significant variables will not be in the functional support of the + resulting truth table, but the method is helpful to align a truth table when + being used with another one. + + \param tt Larger truth table to create + \param from Smaller truth table to copy from +*/ +template +void extend_to_inplace( TT& tt, const TTFrom& from ) +{ + assert( tt.num_vars() >= from.num_vars() ); + + if ( from.num_vars() < 6 ) + { + auto mask = *from.begin(); + + for ( auto i = from.num_vars(); i < std::min( 6, tt.num_vars() ); ++i ) + { + mask |= ( mask << ( 1 << i ) ); + } + + std::fill( tt.begin(), tt.end(), mask ); + } + else + { + auto it = tt.begin(); + while ( it != tt.end() ) + { + it = std::copy( from.cbegin(), from.cend(), it ); + } + } +} + +/*! \brief Extends smaller truth table to larger static one + + This is an out-of-place version of `extend_to_inplace` that has the truth + table as a return value. It only works for creating static truth tables. The + template parameter `NumVars` must be equal or larger to the number of + variables in `from`. + + \param from Smaller truth table to copy from +*/ +template +inline static_truth_table extend_to( const TTFrom& from ) +{ + static_truth_table tt; + extend_to_inplace( tt, from ); + return tt; +} + +/*! \brief Checks whether truth table depends on given variable index + + \param tt Truth table + \param var_index Variable index +*/ +template +bool has_var( const TT& tt, uint8_t var_index ) +{ + assert( var_index < tt.num_vars() ); + + if ( tt.num_vars() <= 6 || var_index < 6 ) + { + return std::any_of( std::begin( tt._bits ), std::end( tt._bits ), + [var_index]( uint64_t word ) + { return ( ( word >> ( uint64_t( 1 ) << var_index ) ) & detail::projections_neg[var_index] ) != + ( word & detail::projections_neg[var_index] ); } ); + } + + const auto step = 1 << ( var_index - 6 ); + for ( auto i = 0u; i < static_cast( tt.num_blocks() ); i += 2 * step ) + { + for ( auto j = 0; j < step; ++j ) + { + if ( tt._bits[i + j] != tt._bits[i + j + step] ) + { + return true; + } + } + } + return false; +} + +/*! \brief Checks whether truth table depends on given variable index + + \param tt Truth table + \param care Care set + \param var_index Variable index +*/ +template +bool has_var( const TT& tt, const TT& care, uint8_t var_index ) +{ + assert( var_index < tt.num_vars() ); + assert( tt.num_vars() == care.num_vars() ); + + if ( tt.num_vars() <= 6 || var_index < 6 ) + { + auto it_tt = std::begin( tt._bits ); + auto it_care = std::begin( care._bits ); + while ( it_tt != std::end( tt._bits ) ) + { + if ( ( ( ( *it_tt >> ( uint64_t( 1 ) << var_index ) ) ^ *it_tt ) & detail::projections_neg[var_index] + & ( *it_care >> ( uint64_t( 1 ) << var_index ) ) & *it_care ) != 0 ) + { + return true; + } + ++it_tt; + ++it_care; + } + + return false; + } + + const auto step = 1 << ( var_index - 6 ); + for ( auto i = 0u; i < static_cast( tt.num_blocks() ); i += 2 * step ) + { + for ( auto j = 0; j < step; ++j ) + { + if ( ( ( tt._bits[i + j] ^ tt._bits[i + j + step] ) & care._bits[i + j] & care._bits[i + j + step] ) != 0 ) + { + return true; + } + } + } + return false; +} + +/*! \brief Shrinks larger truth table to smaller one + + The function expects that the most significant bits, which are cut off, are + not in the functional support of the original function. Only then it is + ensured that the resulting function is equivalent. + + \param tt Smaller truth table to create + \param from Larger truth table to copy from +*/ +template +void shrink_to_inplace( TT& tt, const TTFrom& from ) +{ + assert( tt.num_vars() <= from.num_vars() ); + + std::copy( from.begin(), from.begin() + tt.num_blocks(), tt.begin() ); + + if ( tt.num_vars() < 6 ) + { + tt.mask_bits(); + } +} + +/*! \brief Shrinks larger truth table to smaller dynamic one + + This is an out-of-place version of `shrink_to` that has the truth table as a + return value. It only works for creating dynamic tables. The parameter + `num_vars` must be equal or smaller to the number of variables in `from`. + + \param from Smaller truth table to copy from +*/ +template +inline dynamic_truth_table shrink_to( const TTFrom& from, unsigned num_vars ) +{ + auto tt = create( num_vars ); + shrink_to_inplace( tt, from ); + return tt; +} + +/*! \brief Prints truth table in hexadecimal representation + + The most-significant bit will be the first character of the string. + + \param tt Truth table + \param os Output stream +*/ +template +void print_hex( const TT& tt, std::ostream& os = std::cout ) +{ + auto const chunk_size = + std::min( tt.num_vars() <= 1 ? 1 : ( tt.num_bits() >> 2 ), 16 ); + + for_each_block_reversed( tt, [&os, chunk_size]( auto word ) + { + std::string chunk( chunk_size, '0' ); + + auto it = chunk.rbegin(); + while (word && it != chunk.rend()) { + auto hex = word & 0xf; + if (hex < 10) { + *it = '0' + static_cast(hex); + } else { + *it = 'a' + static_cast(hex - 10); + } + ++it; + word >>= 4; + } + os << chunk; } ); +} + +} //namespace kitty + +#endif // _KITTY_OPERATIONS_TT_H_ \ No newline at end of file diff --git a/src/acd/kitty_operators.hpp b/src/acd/kitty_operators.hpp new file mode 100644 index 0000000000..cf973ebe01 --- /dev/null +++ b/src/acd/kitty_operators.hpp @@ -0,0 +1,86 @@ +#ifndef _KITTY_OPERATORS_TT_H_ +#define _KITTY_OPERATORS_TT_H_ +#pragma once + +#include +#include +#include +#include +#include + +#include "kitty_constants.hpp" +#include "kitty_dynamic_tt.hpp" +#include "kitty_static_tt.hpp" +#include "kitty_operations.hpp" + +namespace kitty +{ + +/*! \brief Operator for unary_not */ +inline dynamic_truth_table operator~( const dynamic_truth_table& tt ) +{ + return unary_not( tt ); +} + +/*! \brief Operator for unary_not */ +template +inline static_truth_table operator~( const static_truth_table& tt ) +{ + return unary_not( tt ); +} + +/*! \brief Operator for binary_and */ +inline dynamic_truth_table operator&( const dynamic_truth_table& first, const dynamic_truth_table& second ) +{ + return binary_and( first, second ); +} + +/*! \brief Operator for binary_and */ +template +inline static_truth_table operator&( const static_truth_table& first, const static_truth_table& second ) +{ + return binary_and( first, second ); +} + +/*! \brief Operator for binary_and and assign */ +inline void operator&=( dynamic_truth_table& first, const dynamic_truth_table& second ) +{ + first = binary_and( first, second ); +} + +/*! \brief Operator for binary_and and assign */ +template +inline void operator&=( static_truth_table& first, const static_truth_table& second ) +{ + first = binary_and( first, second ); +} + +/*! \brief Operator for binary_or */ +inline dynamic_truth_table operator|( const dynamic_truth_table& first, const dynamic_truth_table& second ) +{ + return binary_or( first, second ); +} + +/*! \brief Operator for binary_or */ +template +inline static_truth_table operator|( const static_truth_table& first, const static_truth_table& second ) +{ + return binary_or( first, second ); +} + +/*! \brief Operator for binary_or and assign */ +inline void operator|=( dynamic_truth_table& first, const dynamic_truth_table& second ) +{ + first = binary_or( first, second ); +} + +/*! \brief Operator for binary_or and assign */ +template +inline void operator|=( static_truth_table& first, const static_truth_table& second ) +{ + first = binary_or( first, second ); +} + +} // namespace kitty + +#endif // _KITTY_OPERATORS_TT_H_ \ No newline at end of file diff --git a/src/acd/kitty_static_tt.hpp b/src/acd/kitty_static_tt.hpp new file mode 100644 index 0000000000..61593f3ff1 --- /dev/null +++ b/src/acd/kitty_static_tt.hpp @@ -0,0 +1,131 @@ +#ifndef _KITTY_STATIC_TT_H_ +#define _KITTY_STATIC_TT_H_ +#pragma once + +#include +#include + +#include "kitty_constants.hpp" + +namespace kitty +{ + +template +struct static_truth_table +{ + /*! \cond PRIVATE */ + enum + { + NumBlocks = ( NumVars <= 6 ) ? 1u : ( 1u << ( NumVars - 6 ) ) + }; + + enum + { + NumBits = uint64_t( 1 ) << NumVars + }; + /*! \endcond */ + + /*! Standard constructor. + + The number of variables provided to the truth table must be known + at runtime. The number of blocks will be computed as a compile + time constant. + */ + static_truth_table() + { + _bits.fill( 0 ); + } + + /*! Constructs a new static truth table instance with the same number of variables. */ + inline static_truth_table construct() const + { + return static_truth_table(); + } + + /*! Returns number of variables. + */ + inline auto num_vars() const noexcept { return NumVars; } + + /*! Returns number of blocks. + */ + inline auto num_blocks() const noexcept { return NumBlocks; } + + /*! Returns number of bits. + */ + inline auto num_bits() const noexcept { return NumBits; } + + /*! \brief Begin iterator to bits. + */ + inline auto begin() noexcept { return _bits.begin(); } + + /*! \brief End iterator to bits. + */ + inline auto end() noexcept { return _bits.end(); } + + /*! \brief Begin iterator to bits. + */ + inline auto begin() const noexcept { return _bits.begin(); } + + /*! \brief End iterator to bits. + */ + inline auto end() const noexcept { return _bits.end(); } + + /*! \brief Reverse begin iterator to bits. + */ + inline auto rbegin() noexcept { return _bits.rbegin(); } + + /*! \brief Reverse end iterator to bits. + */ + inline auto rend() noexcept { return _bits.rend(); } + + /*! \brief Constant begin iterator to bits. + */ + inline auto cbegin() const noexcept { return _bits.cbegin(); } + + /*! \brief Constant end iterator to bits. + */ + inline auto cend() const noexcept { return _bits.cend(); } + + /*! \brief Constant reverse begin iterator to bits. + */ + inline auto crbegin() const noexcept { return _bits.crbegin(); } + + /*! \brief Constant teverse end iterator to bits. + */ + inline auto crend() const noexcept { return _bits.crend(); } + + /*! \brief Assign other truth table if number of variables match. + + This replaces the current truth table with another truth table, if `other` + has the same number of variables. Otherwise, the truth table is not + changed. + + \param other Other truth table + */ + template + static_truth_table& operator=( const TT& other ) + { + if ( other.num_bits() == num_bits() ) + { + std::copy( other.begin(), other.end(), begin() ); + } + + return *this; + } + + /*! Masks the number of valid truth table bits. + + We know that we will have at least 7 variables in this data + structure. + */ + inline void mask_bits() noexcept {} + + /*! \cond PRIVATE */ +public: /* fields */ + std::array _bits; + /*! \endcond */ +}; + +} //namespace kitty + +#endif // _KITTY_STATIC_TT_H_ \ No newline at end of file diff --git a/src/acd/module.make b/src/acd/module.make new file mode 100644 index 0000000000..b245d2c423 --- /dev/null +++ b/src/acd/module.make @@ -0,0 +1 @@ +SRC += src/acd/ac_wrapper.cpp diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index c8e2b1ef8a..33b85e0bf0 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -19447,7 +19447,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) If_ManSetDefaultPars( pPars ); pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut(); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYDEWSqaflepmrsdbgxyzuojiktncvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYDEWSqaflepmrsdbgxyuojiktnczvh" ) ) != EOF ) { switch ( c ) { @@ -19652,9 +19652,6 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'y': pPars->fUserRecLib ^= 1; break; - case 'z': - pPars->fUserLutDec ^= 1; - break; case 'u': pPars->fUserSesLib ^= 1; break; @@ -19679,6 +19676,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'c': pPars->fUseTtPerm ^= 1; break; + case 'z': + pPars->fAcd ^= 1; + break; case 'v': pPars->fVerbose ^= 1; break; @@ -19810,7 +19810,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) pPars->pLutLib = NULL; } // modify for delay optimization - if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut || pPars->fUserLutDec ) + if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut || pPars->fAcd ) { pPars->fTruth = 1; pPars->fCutMin = 1; @@ -19956,7 +19956,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) sprintf(LutSize, "library" ); else sprintf(LutSize, "%d", pPars->nLutSize ); - Abc_Print( -2, "usage: if [-KCFAGRNTXY num] [-DEW float] [-S str] [-qarlepmsdbgxyzuojiktncvh]\n" ); + Abc_Print( -2, "usage: if [-KCFAGRNTXY num] [-DEW float] [-S str] [-qarlepmsdbgxyuojiktncvh]\n" ); Abc_Print( -2, "\t performs FPGA technology mapping of the network\n" ); Abc_Print( -2, "\t-K num : the number of LUT inputs (2 < num < %d) [default = %s]\n", IF_MAX_LUTSIZE+1, LutSize ); Abc_Print( -2, "\t-C num : the max number of priority cuts (0 < num < 2^12) [default = %d]\n", pPars->nCutsMax ); @@ -19985,7 +19985,6 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-g : toggles delay optimization by SOP balancing [default = %s]\n", pPars->fDelayOpt? "yes": "no" ); Abc_Print( -2, "\t-x : toggles delay optimization by DSD balancing [default = %s]\n", pPars->fDsdBalance? "yes": "no" ); Abc_Print( -2, "\t-y : toggles delay optimization with recorded library [default = %s]\n", pPars->fUserRecLib? "yes": "no" ); - Abc_Print( -2, "\t-z : toggles delay optimization with LUT decomposition [default = %s]\n", pPars->fUserLutDec? "yes": "no" ); Abc_Print( -2, "\t-u : toggles delay optimization with SAT-based library [default = %s]\n", pPars->fUserSesLib? "yes": "no" ); Abc_Print( -2, "\t-o : toggles using buffers to decouple combinational outputs [default = %s]\n", pPars->fUseBuffs? "yes": "no" ); Abc_Print( -2, "\t-j : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck07? "yes": "no" ); @@ -19994,6 +19993,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-t : toggles optimizing average rather than maximum level [default = %s]\n", pPars->fDoAverage? "yes": "no" ); Abc_Print( -2, "\t-n : toggles computing DSDs of the cut functions [default = %s]\n", pPars->fUseDsd? "yes": "no" ); Abc_Print( -2, "\t-c : toggles computing truth tables in a new way [default = %s]\n", pPars->fUseTtPerm? "yes": "no" ); + Abc_Print( -2, "\t-z : toggles using ACD decomposition [default = %s]\n", pPars->fAcd? "yes": "no" ); Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", pPars->fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : prints the command usage\n"); return 1; diff --git a/src/base/abci/abcIf.c b/src/base/abci/abcIf.c index e92a2282ee..079cd0066a 100644 --- a/src/base/abci/abcIf.c +++ b/src/base/abci/abcIf.c @@ -116,7 +116,7 @@ Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars ) pPars->pTimesReq = Abc_NtkGetCoRequiredFloats(pNtk); // update timing info to reflect logic level - if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib || pPars->fUserLutDec) && pNtk->pManTime ) + if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib || pPars->fAcd) && pNtk->pManTime ) { int c; if ( pNtk->AndGateDelay == 0.0 ) @@ -427,28 +427,143 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC } /**Function************************************************************* + Synopsis [Implements decomposed LUT-structure of the cut.] + Description [] + + SideEffects [] + SeeAlso [] + ***********************************************************************/ + void Abc_DecRecordToHop( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Cut_t * pCutBest, If_Obj_t * pIfObj, Vec_Int_t * vCover, Abc_Obj_t * pNodeTop ) + { + extern Hop_Obj_t * Kit_TruthToHop( Hop_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory ); + assert( !pIfMan->pPars->fUseTtPerm ); - Synopsis [Implements decomposed LUT-structure of the cut.] + // get the truth table + word * pTruth = If_CutTruthW(pIfMan, pCutBest); + int v; + If_Obj_t * pIfLeaf; - Description [] - - SideEffects [] + if ( pCutBest->nLeaves <= 6 ) + { + /* add fanins */ + If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, v ) + Abc_ObjAddFanin( pNodeTop, (Abc_Obj_t *)If_ObjCopy( pIfLeaf ) ); + + pNodeTop->Level = Abc_ObjLevelNew( pNodeTop ); - SeeAlso [] + pNodeTop->pData = Kit_TruthToHop( (Hop_Man_t *)pNtkNew->pManFunc, (unsigned *)pTruth, If_CutLeaveNum(pCutBest), vCover ); + return; + } + + // get the delay profile + unsigned delayProfile = pCutBest->acdDelay; + + // If_Obj_t * pLeaf; + // int i, leafDelay; + // int DelayMax = -1, nLeafMax = 0; + // unsigned uLeafMask = 0; + + // If_CutForEachLeaf( pIfMan, pCutBest, pLeaf, i ) + // { + // leafDelay = If_ObjCutBest(pLeaf)->Delay; + + // if ( DelayMax < leafDelay ) + // { + // DelayMax = leafDelay; + // nLeafMax = 1; + // uLeafMask = (1 << i); + // } + // else if ( DelayMax == leafDelay ) + // { + // nLeafMax++; + // uLeafMask |= (1 << i); + // } + // } -***********************************************************************/ -Hop_Obj_t * Abc_DecRecordToHop( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCutBest, If_Obj_t * pIfObj, Vec_Int_t * vCover ) -{ - // get the truth table // perform LUT-decomposition and return the LUT-structure + unsigned char decompArray[92]; + int val = acd_decompose( pTruth, pCutBest->nLeaves, 6, &(delayProfile), decompArray ); + + assert( val == 0 ); + // assert( DelayMax + 2 >= pCutBest->Delay ); + // convert the LUT-structure into a set of logic nodes in Abc_Ntk_t + unsigned char bytes_check = decompArray[0]; + assert( bytes_check <= 92 ); + + int byte_p = 2; + unsigned char i, j, k, num_fanins, num_words, num_bytes; + int level, fanin; + word *tt; + Abc_Obj_t *pNewNodes[5]; + + /* create intermediate LUTs*/ + assert( decompArray[1] - 1 <= 5 ); + Abc_Obj_t * pFanin; + for ( i = 0; i < decompArray[1]; ++i ) + { + if ( i < decompArray[1] - 1 ) + { + pNewNodes[i] = Abc_NtkCreateNode( pNtkNew ); + } + else + { + pNewNodes[i] = pNodeTop; + } + num_fanins = decompArray[byte_p++]; + level = 0; + for ( j = 0; j < num_fanins; ++j ) + { + fanin = (int)decompArray[byte_p++]; + if ( fanin < If_CutLeaveNum(pCutBest) ) + { + pFanin = (Abc_Obj_t *)If_ObjCopy( If_CutLeaf(pIfMan, pCutBest, fanin) ); + } + else + { + assert( fanin - If_CutLeaveNum(pCutBest) < i ); + pFanin = pNewNodes[fanin - If_CutLeaveNum(pCutBest)]; + } + Abc_ObjAddFanin( pNewNodes[i], pFanin ); + level = Abc_MaxInt( level, Abc_ObjLevel(pFanin) ); + } + + pNewNodes[i]->Level = level + (int)(Abc_ObjFaninNum(pNewNodes[i]) > 0); + + /* extract the truth table */ + tt = pIfMan->puTempW; + num_words = ( num_fanins <= 6 ) ? 1 : ( 1 << ( num_fanins - 6 ) ); + num_bytes = ( num_fanins <= 3 ) ? 1 : ( 1 << ( Abc_MinInt( (int)num_fanins, 6 ) - 3 ) ); + for ( j = 0; j < num_words; ++j ) + { + tt[j] = 0; + for ( k = 0; k < num_bytes; ++k ) + { + tt[j] |= ( (word)(decompArray[byte_p++]) ) << ( k << 3 ); + } + } + + /* extend truth table if size < 5 */ + assert( num_fanins != 1 ); + if ( num_fanins == 2 ) + { + tt[0] |= tt[0] << 4; + } + while ( num_bytes < 4 ) + { + tt[0] |= tt[0] << ( num_bytes << 3 ); + num_bytes <<= 1; + } + + /* add node data */ + pNewNodes[i]->pData = Kit_TruthToHop( (Hop_Man_t *)pNtkNew->pManFunc, (unsigned *)tt, (int) num_fanins, vCover ); + } + + /* check correct read */ + assert( byte_p == decompArray[0] ); // this is a placeholder, which takes the truth table and converts it into an AIG without LUT-decomposition - extern Hop_Obj_t * Kit_TruthToHop( Hop_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory ); - word * pTruth = If_CutTruthW(pIfMan, pCutBest); - assert( !pIfMan->pPars->fUseTtPerm ); - return Kit_TruthToHop( (Hop_Man_t *)pMan, (unsigned *)pTruth, If_CutLeaveNum(pCutBest), vCover ); -} + } /**Function************************************************************* @@ -488,13 +603,18 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t pNodeNew = Abc_NtkCreateNode( pNtkNew ); // if ( pIfMan->pPars->pLutLib && pIfMan->pPars->pLutLib->fVarPinDelays ) if ( !pIfMan->pPars->fDelayOpt && !pIfMan->pPars->fDelayOptLut && !pIfMan->pPars->fDsdBalance && !pIfMan->pPars->fUseTtPerm && - !pIfMan->pPars->pLutStruct && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->fUserLutDec && !pIfMan->pPars->nGateSize ) + !pIfMan->pPars->pLutStruct && !pIfMan->pPars->fAcd && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->nGateSize ) If_CutRotatePins( pIfMan, pCutBest ); if ( pIfMan->pPars->fUseCnfs || pIfMan->pPars->fUseMv ) { If_CutForEachLeafReverse( pIfMan, pCutBest, pIfLeaf, i ) Abc_ObjAddFanin( pNodeNew, Abc_NodeFromIf_rec(pNtkNew, pIfMan, pIfLeaf, vCover) ); } + else if ( pIfMan->pPars->fAcd ) + { + If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, i ) + Abc_NodeFromIf_rec(pNtkNew, pIfMan, pIfLeaf, vCover); + } else { If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, i ) @@ -548,10 +668,10 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t extern Hop_Obj_t * Abc_RecToHop3( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj ); pNodeNew->pData = Abc_RecToHop3( (Hop_Man_t *)pNtkNew->pManFunc, pIfMan, pCutBest, pIfObj ); } - else if ( pIfMan->pPars->fUserLutDec ) + else if ( pIfMan->pPars->fAcd ) { - extern Hop_Obj_t * Abc_DecRecordToHop( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj, Vec_Int_t * vMemory ); - pNodeNew->pData = Abc_DecRecordToHop( (Hop_Man_t *)pNtkNew->pManFunc, pIfMan, pCutBest, pIfObj, vCover ); + extern void Abc_DecRecordToHop( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj, Vec_Int_t * vMemory, Abc_Obj_t * pNodeTop ); + Abc_DecRecordToHop( pNtkNew, pIfMan, pCutBest, pIfObj, vCover, pNodeNew ); } else { diff --git a/src/map/if/if.h b/src/map/if/if.h index 93cb0f6caf..156e8679f3 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -40,6 +40,7 @@ #include "opt/dau/dau.h" #include "misc/vec/vecHash.h" #include "misc/vec/vecWec.h" +#include "ACD/ac_wrapper.h" ABC_NAMESPACE_HEADER_START @@ -126,7 +127,6 @@ struct If_Par_t_ int fDsdBalance; // special delay optimization int fUserRecLib; // use recorded library int fUserSesLib; // use SAT-based synthesis - int fUserLutDec; // use LUT-based decomposition int fBidec; // use bi-decomposition int fUse34Spec; // use specialized matching int fUseBat; // use one specialized feature @@ -146,6 +146,7 @@ struct If_Par_t_ int fDeriveLuts; // enables deriving LUT structures int fDoAverage; // optimize average rather than maximum level int fHashMapping; // perform AIG hashing after mapping + int fAcd; // perform AIG hashing after mapping int fVerbose; // the verbosity flag int fVerboseTrace; // the verbosity flag char * pLutStruct; // LUT structure @@ -280,6 +281,7 @@ struct If_Man_t_ int pDumpIns[16]; Vec_Str_t * vMarks; Vec_Int_t * vVisited2; + int useLimitAdc; // timing manager Tim_Man_t * pManTim; @@ -303,6 +305,7 @@ struct If_Cut_t_ int iCutFunc; // TT ID of the cut int uMaskFunc; // polarity bitmask unsigned uSign; // cut signature + unsigned acdDelay; // Computed pin delay during ACD unsigned Cost : 12; // the user's cost of the cut (related to IF_COST_MAX) unsigned fCompl : 1; // the complemented attribute unsigned fUser : 1; // using the user's area and delay @@ -552,6 +555,7 @@ extern int If_CutPerformCheck45( If_Man_t * p, unsigned * pTruth, in extern int If_CutPerformCheck54( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr ); extern int If_CutPerformCheck75( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr ); extern float If_CutDelayLutStruct( If_Man_t * p, If_Cut_t * pCut, char * pStr, float WireDelay ); +// extern int If_CutPerformAcd( If_Man_t * p, unsigned nVars, int lutSize, unsigned * pdelay, int use_late_arrival, unsigned * cost ); extern int If_CluCheckExt( void * p, word * pTruth, int nVars, int nLutLeaf, int nLutRoot, char * pLut0, char * pLut1, word * pFunc0, word * pFunc1 ); extern int If_CluCheckExt3( void * p, word * pTruth, int nVars, int nLutLeaf, int nLutLeaf2, int nLutRoot, @@ -566,6 +570,9 @@ extern int If_CutSopBalancePinDelaysInt( Vec_Int_t * vCover, int * p extern int If_CutSopBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); extern int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ); extern int If_CutLutBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); +extern int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay ); +extern int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ); +extern float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required ); /*=== ifDsd.c =============================================================*/ extern If_DsdMan_t * If_DsdManAlloc( int nVars, int nLutSize ); extern void If_DsdManAllocIsops( If_DsdMan_t * p, int nLutSize ); @@ -693,6 +700,8 @@ extern int If_ManCountSpecialPos( If_Man_t * p ); extern void If_CutTraverse( If_Man_t * p, If_Obj_t * pRoot, If_Cut_t * pCut, Vec_Ptr_t * vNodes ); extern void If_ObjPrint( If_Obj_t * pObj ); +extern int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost ); +extern int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ); ABC_NAMESPACE_HEADER_END diff --git a/src/map/if/ifCore.c b/src/map/if/ifCore.c index c03061af20..a8e482912d 100644 --- a/src/map/if/ifCore.c +++ b/src/map/if/ifCore.c @@ -62,6 +62,7 @@ void If_ManSetDefaultPars( If_Par_t * pPars ) pPars->fPower = 0; pPars->fCutMin = 0; pPars->fBidec = 0; + pPars->fAcd = 0; pPars->fVerbose = 0; } @@ -106,9 +107,16 @@ int If_ManPerformMappingComb( If_Man_t * p ) If_Obj_t * pObj; abctime clkTotal = Abc_Clock(); int i; + p->useLimitAdc = 1; + //p->vVisited2 = Vec_IntAlloc( 100 ); //p->vMarks = Vec_StrStart( If_ManObjNum(p) ); + // if ( p->pPars->fAcd ) + // { + // p->pPars->nLutSize = 6; + // } + // set arrival times and fanout estimates If_ManForEachCi( p, pObj, i ) { @@ -121,6 +129,16 @@ int If_ManPerformMappingComb( If_Man_t * p ) { // map for delay If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 1, "Delay" ); + + if ( p->pPars->fAcd ) + { + // p->pPars->nLutSize = oldLutSize; + p->useLimitAdc = 0; + If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 0, "Delay" ); + p->useLimitAdc = 1; + // p->pPars->nLutSize = 6; + } + // map for delay second option p->pPars->fFancy = 1; If_ManResetOriginalRefs( p ); diff --git a/src/map/if/ifCut.c b/src/map/if/ifCut.c index f4f72d1c8d..8d1cccba08 100644 --- a/src/map/if/ifCut.c +++ b/src/map/if/ifCut.c @@ -604,10 +604,6 @@ static inline int If_ManSortCompare( If_Man_t * p, If_Cut_t * pC0, If_Cut_t * pC return -1; if ( pC0->nLeaves > pC1->nLeaves ) return 1; - if ( pC0->Delay < pC1->Delay - p->fEpsilon ) - return -1; - if ( pC0->Delay > pC1->Delay + p->fEpsilon ) - return 1; if ( pC0->fUseless < pC1->fUseless ) return -1; if ( pC0->fUseless > pC1->fUseless ) @@ -765,7 +761,7 @@ void If_CutSort( If_Man_t * p, If_Set_t * pCutSet, If_Cut_t * pCut ) if ( !pCut->fUseless && (p->pPars->fUseDsd || p->pPars->pFuncCell2 || p->pPars->fUseBat || - p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || + p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fAcd || p->pPars->fEnableCheck07 || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->fUseDsdTune || p->pPars->fEnableCheck75 || p->pPars->fEnableCheck75u || p->pPars->fUseCheck1 || p->pPars->fUseCheck2) ) { diff --git a/src/map/if/ifDelay.c b/src/map/if/ifDelay.c index cb25e767ea..fcd53e3485 100644 --- a/src/map/if/ifDelay.c +++ b/src/map/if/ifDelay.c @@ -411,6 +411,132 @@ int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ) return DelayMax + 2; } } + +int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay ) +{ + pCut->fUser = 1; + pCut->Cost = pCut->nLeaves > 1 ? 1 : 0; + pCut->acdDelay = 0; + if ( pCut->nLeaves == 0 ) // const + { + assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 0 ); + return 0; + } + if ( pCut->nLeaves == 1 ) // variable + { + assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 1 ); + return (int)If_ObjCutBest(If_CutLeaf(p, pCut, 0))->Delay; + } + + // int LutSize = p->pPars->pLutStruct[0] - '0'; + int LutSize = 6; + int i, leaf_delay; + int DelayMax = -1, nLeafMax = 0; + unsigned uLeafMask = 0; + for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) + { + leaf_delay = If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay; + + if ( DelayMax < leaf_delay ) + { + DelayMax = leaf_delay; + nLeafMax = 1; + uLeafMask = (1 << i); + } + else if ( DelayMax == leaf_delay ) + { + nLeafMax++; + uLeafMask |= (1 << i); + } + } + if ( If_CutLeaveNum(pCut) <= LutSize ) + { + pCut->acdDelay = ( 1 << LutSize ) - 1; + return DelayMax + 1; + } + // else if ( DelayMax + 1 >= best_delay ) + // { + // return DelayMax + 2; + // } + + /* compute the decomposition */ + int use_late_arrival = DelayMax + 2 >= best_delay; + unsigned cost = 1; + + /* TODO: have checks based on delay */ + if ( use_late_arrival && nLeafMax > LutSize / 2 ) + { + pCut->Cost = IF_COST_MAX; + return ABC_INFINITY; + } + + /* remove from critical set */ + if ( !use_late_arrival ) + uLeafMask = 0; + + + word *pTruth = If_CutTruthW( p, pCut ); + int val = acd_evaluate( pTruth, pCut->nLeaves, LutSize, &uLeafMask, &cost ); + + /* not feasible decomposition */ + pCut->acdDelay = uLeafMask; + if ( val < 0 ) + { + pCut->Cost = IF_COST_MAX; + return ABC_INFINITY; + } + + pCut->Cost = cost; + + return DelayMax + ( use_late_arrival ? 1 : 2 ); +} + +int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ) +{ + // pCut->fUser = 1; + + if ( pCut->nLeaves == 0 ) // const + { + assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 0 ); + return 0; + } + if ( pCut->nLeaves == 1 ) // variable + { + assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 1 ); + return (int)If_ObjCutBest(If_CutLeaf(p, pCut, 0))->Delay; + } + + // int LutSize = p->pPars->pLutStruct[0] - '0'; + int LutSize = 6; + int i, leaf_delay; + int DelayMax = -1, nLeafMax = 0; + unsigned uLeafMask = 0; + for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) + { + leaf_delay = If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay; + leaf_delay += ( ( pCut->acdDelay >> i ) & 1 ) == 0 ? 2 : 1; + DelayMax = Abc_MaxInt( leaf_delay, DelayMax ); + } + + return DelayMax; +} + +float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required ) +{ + if ( pCut->nLeaves == 0 ) // const + { + assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 0 ); + return required; + } + if ( pCut->nLeaves == 1 ) // variable + { + assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 1 ); + return 0; + } + + return ( ( pCut->acdDelay >> i ) & 1 ) == 0 ? 2 : 1; +} + /* int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ) { diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index 4a5210e923..da83b5525c 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -148,32 +148,6 @@ int * If_CutArrTimeProfile( If_Man_t * p, If_Cut_t * pCut ) return p->pArrTimeProfile; } - -/**Function************************************************************* - - Synopsis [Returns the node's delay if its cut it LUT-decomposed.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int If_CutDelayLutDec( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj ) -{ - // get the truth table - // get the cut leaves' arrival times - // run LUT-decomposition in the evaluation mode - // return expected arrival time at the output - - // this is a placeholder code, which is assume the cut has unit delay - int i, ArrTimes = 0; - for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) - ArrTimes = Abc_MaxInt( ArrTimes, (int)If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay ); - return ArrTimes + 1; -} - /**Function************************************************************* Synopsis [Finds the best cut for the given node.] @@ -192,7 +166,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep If_Cut_t * pCut0R, * pCut1R; int fFunc0R, fFunc1R; int i, k, v, iCutDsd, fChange; - int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || + int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fAcd || p->pPars->fUseDsdTune || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->pLutStruct || p->pPars->pFuncCell2 || p->pPars->fUseCheck1 || p->pPars->fUseCheck2; int fUseAndCut = (p->pPars->nAndDelay > 0) || (p->pPars->nAndArea > 0); assert( !If_ObjIsAnd(pObj->pFanin0) || pObj->pFanin0->pCutSet->nCuts > 0 ); @@ -234,8 +208,10 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->fUseless = 1; } } - else if ( p->pPars->fUserLutDec ) - pCut->Delay = If_CutDelayLutDec( p, pCut, pObj ); + else if ( p->pPars->fAcd ) + { + pCut->Delay = If_AcdReEval( p, pCut ); + } else if ( p->pPars->fDelayOptLut ) pCut->Delay = If_CutLutBalanceEval( p, pCut ); else if( p->pPars->nGateSize > 0 ) @@ -292,6 +268,8 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep if ( !If_CutMergeOrdered( p, pCut0, pCut1, pCut ) ) continue; } + if ( p->pPars->fAcd && p->useLimitAdc && pCut->nLeaves > 6 ) + continue; if ( pObj->fSpec && pCut->nLeaves == (unsigned)p->pPars->nLutSize ) continue; p->nCutsMerged++; @@ -450,7 +428,12 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep else if ( p->pPars->fDsdBalance ) pCut->Delay = If_CutDsdBalanceEval( p, pCut, NULL ); else if ( p->pPars->fUserRecLib ) - pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); + pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); + else if ( p->pPars->fAcd ) + { + pCut->Delay = If_AcdEval( p, pCut, fFirst ? ABC_INFINITY : (int) If_ObjCutBest(pObj)->Delay ); + pCut->fUseless = pCut->Delay == ABC_INFINITY; + } else if ( p->pPars->fUserSesLib ) { int Cost = 0; @@ -464,8 +447,6 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->fUseless = 1; } } - else if ( p->pPars->fUserLutDec ) - pCut->Delay = If_CutDelayLutDec( p, pCut, pObj ); else if ( p->pPars->fDelayOptLut ) pCut->Delay = If_CutLutBalanceEval( p, pCut ); else if( p->pPars->nGateSize > 0 ) @@ -537,7 +518,7 @@ void If_ObjPerformMappingChoice( If_Man_t * p, If_Obj_t * pObj, int Mode, int fP If_Set_t * pCutSet; If_Obj_t * pTemp; If_Cut_t * pCutTemp, * pCut; - int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fUse34Spec; + int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUse34Spec || p->pPars->fAcd; assert( pObj->pEquiv != NULL ); // prepare diff --git a/src/map/if/ifTime.c b/src/map/if/ifTime.c index 9ceef1475e..9bce5bc434 100644 --- a/src/map/if/ifTime.c +++ b/src/map/if/ifTime.c @@ -211,6 +211,12 @@ void If_CutPropagateRequired( If_Man_t * p, If_Obj_t * pObj, If_Cut_t * pCut, fl pLeaf->Required = IF_MIN( pLeaf->Required, Required - pLutDelays[0] ); } } + else if ( p->pPars->fAcd ) + { + Required = ObjRequired; + If_CutForEachLeaf( p, pCut, pLeaf, i ) + pLeaf->Required = IF_MIN( pLeaf->Required, Required - If_AcdLeafProp( p, pCut, i, ObjRequired ) ); + } else { if ( pCut->fUser ) From 66cdd36d20afea221ac9af47866569a9bf038f30 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Wed, 15 Nov 2023 19:03:29 +0100 Subject: [PATCH 34/67] Runtime improvements in decomposition --- src/acd/ac_decomposition.hpp | 4 ++-- src/acd/ac_wrapper.cpp | 4 ++-- src/acd/ac_wrapper.h | 1 + src/acd/kitty_operators.hpp | 38 +++++++++++++++++++++++++++++++++++- src/map/if/if.h | 2 +- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 4f94bcba4b..59fd00ada1 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -134,8 +134,8 @@ class ac_decomposition_impl /* add cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; - /* check for feasible solution that improves the cost */ - if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost ) + /* check for feasible solution that improves the cost */ /* TODO: remove limit on cost */ + if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 12 ) { best_tt = tt_p; permutations = perm; diff --git a/src/acd/ac_wrapper.cpp b/src/acd/ac_wrapper.cpp index b7cee0dd75..aabe8e86fb 100644 --- a/src/acd/ac_wrapper.cpp +++ b/src/acd/ac_wrapper.cpp @@ -20,8 +20,8 @@ int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, ac_decomposition_stats st; ac_decomposition_impl acd( tt, nVars, ps, &st ); - acd.run( *pdelay ); - int val = acd.compute_decomposition(); + int val = acd.run( *pdelay ); + // int val = acd.compute_decomposition(); if ( val < 0 ) { diff --git a/src/acd/ac_wrapper.h b/src/acd/ac_wrapper.h index 522a60b865..cb22acf801 100644 --- a/src/acd/ac_wrapper.h +++ b/src/acd/ac_wrapper.h @@ -4,6 +4,7 @@ // #include "base/main/main.h" #include "misc/util/abc_global.h" +#include "map/if/if.h" // ABC_NAMESPACE_HEADER_START diff --git a/src/acd/kitty_operators.hpp b/src/acd/kitty_operators.hpp index cf973ebe01..68a24cf2ec 100644 --- a/src/acd/kitty_operators.hpp +++ b/src/acd/kitty_operators.hpp @@ -78,7 +78,43 @@ inline void operator|=( dynamic_truth_table& first, const dynamic_truth_table& s template inline void operator|=( static_truth_table& first, const static_truth_table& second ) { - first = binary_or( first, second ); + // first = binary_or( first, second ); + /* runtime improved version */ + if constexpr ( NumVars <= 6 ) + { + first._bits |= second._bits; + first.mask_bits(); + } + else if constexpr ( NumVars == 7 ) + { + first._bits[0] |= second._bits[0]; + first._bits[1] |= second._bits[1]; + } + else if constexpr ( NumVars == 8 ) + { + first._bits[0] |= second._bits[0]; + first._bits[1] |= second._bits[1]; + first._bits[2] |= second._bits[2]; + first._bits[3] |= second._bits[3]; + } + else if constexpr ( NumVars == 9 ) + { + first._bits[0] |= second._bits[0]; + first._bits[1] |= second._bits[1]; + first._bits[2] |= second._bits[2]; + first._bits[3] |= second._bits[3]; + first._bits[4] |= second._bits[4]; + first._bits[5] |= second._bits[5]; + first._bits[6] |= second._bits[6]; + first._bits[7] |= second._bits[7]; + } + else + { + for ( uint32_t i = 0; i < first.num_blocks(); ++i ) + { + first._bits[i] |= second._bits[i]; + } + } } } // namespace kitty diff --git a/src/map/if/if.h b/src/map/if/if.h index 156e8679f3..56f0bb7edf 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -40,7 +40,7 @@ #include "opt/dau/dau.h" #include "misc/vec/vecHash.h" #include "misc/vec/vecWec.h" -#include "ACD/ac_wrapper.h" +#include "acd/ac_wrapper.h" ABC_NAMESPACE_HEADER_START From c07080f818a8982d68aa428ebd81bb490c89ed02 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Wed, 15 Nov 2023 21:32:34 +0100 Subject: [PATCH 35/67] Adding heuristic set covering solver --- src/acd/ac_decomposition.hpp | 225 ++++++++++++++++++++++++++++++++--- 1 file changed, 208 insertions(+), 17 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 59fd00ada1..5a93c5f354 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -84,7 +84,7 @@ class ac_decomposition_impl uint64_t column{ 0 }; uint32_t cost{ 0 }; uint32_t index{ 0 }; - uint32_t sort_cost{ 0 }; + float sort_cost{ 0 }; }; private: @@ -129,6 +129,7 @@ class ac_decomposition_impl uint32_t offset = std::max( static_cast( late_arriving ), 1u ); for ( uint32_t i = offset; i <= ps.lut_size / 2 && i <= 3; ++i ) { + /* TODO: add shared set */ auto evaluate_fn = [&]( STT const& tt ) { return column_multiplicity( tt, i ); }; auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, evaluate_fn, false ); @@ -179,12 +180,22 @@ class ac_decomposition_impl std::vector isets = compute_isets( best_free_set ); generate_support_minimization_encodings(); - solve_min_support_exact( isets, best_free_set ); + + /* always solves exactly for power of 2 */ + if ( __builtin_popcount( best_multiplicity ) == 1 ) + solve_min_support_exact( isets, best_free_set ); + else + solve_min_support_heuristic( isets, best_free_set ); /* unfeasible decomposition */ if ( best_bound_sets.empty() ) { - return -1; + solve_min_support_exact( isets, best_free_set ); + + if ( best_bound_sets.empty() ) + { + return -1; + } } return 0; @@ -995,7 +1006,7 @@ class ac_decomposition_impl } /* solve the covering problem */ - std::array solution = covering_solve_exact( matrix, 100, ps.max_iter ); + std::array solution = covering_solve_exact( matrix, 100, ps.max_iter ); /* check for failed decomposition */ if ( solution[0] == UINT32_MAX ) @@ -1047,6 +1058,72 @@ class ac_decomposition_impl } } + void solve_min_support_heuristic( std::vector const& isets, uint32_t free_set_size ) + { + std::vector matrix; + matrix.reserve( support_minimization_encodings.size() ); + best_bound_sets.clear(); + + /* create covering matrix */ + if ( !create_covering_matrix( isets, matrix, free_set_size, false ) ) + { + return; + } + + /* solve the covering problem: heuristic pass + local search */ + std::array solution = covering_solve_heuristic( matrix ); + + /* check for failed decomposition */ + if ( solution[0] == UINT32_MAX ) + { + return; + } + + /* compute best bound sets */ + uint32_t num_luts = 1 + solution[4]; + uint32_t num_levels = 2; + uint32_t num_edges = free_set_size + solution[4]; + uint32_t isets_support = num_vars - free_set_size; + best_care_sets.clear(); + best_iset_onset.clear(); + best_iset_offset.clear(); + for ( uint32_t i = 0; i < solution[4]; ++i ) + { + STT tt; + STT care; + + const uint32_t onset = support_minimization_encodings[matrix[solution[i]].index][0]; + const uint32_t offset = support_minimization_encodings[matrix[solution[i]].index][1]; + for ( uint32_t j = 0; j < best_multiplicity; ++j ) + { + if ( ( ( onset >> j ) & 1 ) ) + { + tt |= isets[j]; + } + if ( ( ( offset >> j ) & 1 ) ) + { + care |= isets[j]; + } + } + + care |= tt; + num_edges += matrix[solution[i]].cost & ( ( 1 << isets_support ) - 1 ); + + best_bound_sets.push_back( tt ); + best_care_sets.push_back( care ); + best_iset_onset.push_back( onset ); + best_iset_offset.push_back( offset ); + } + + if ( pst != nullptr ) + { + pst->num_luts = num_luts; + pst->num_levels = num_levels; + pst->num_edges = num_edges; + } + } + + template bool create_covering_matrix( std::vector const& isets, std::vector& matrix, uint32_t free_set_size, bool sort ) { assert( best_multiplicity < 12 ); @@ -1119,7 +1196,15 @@ class ac_decomposition_impl cost |= 1 << iset_support; } - uint32_t sort_cost = cost + ( ( combinations - __builtin_popcountl( column ) ) << num_vars ); + float sort_cost = 0; + if constexpr ( UseHeuristic ) + { + sort_cost = ( (float) cost ) / ( __builtin_popcountl( column ) ); + } + else + { + sort_cost = cost + ( ( combinations - __builtin_popcountl( column ) ) << num_vars ); + } /* insert */ matrix.emplace_back( encoding_matrix{ column, cost, i, sort_cost } ); @@ -1128,10 +1213,10 @@ class ac_decomposition_impl } /* necessary condition for the existance of a solution */ - if ( __builtin_popcountl( sol_existance ) != combinations ) - { - return false; - } + // if ( __builtin_popcountl( sol_existance ) != combinations ) + // { + // return false; + // } if ( !sort ) { @@ -1154,7 +1239,7 @@ class ac_decomposition_impl return true; } - template + template std::array covering_solve_exact( std::vector& matrix, uint32_t max_iter = 100, int32_t limit = 2000 ) { /* last value of res contains the size of the bound set */ @@ -1195,7 +1280,14 @@ class ac_decomposition_impl /* limit */ if constexpr ( limit_iter ) { - if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + if ( limit <= 0 ) + { + looping = false; + } + } + if constexpr ( limit_sol ) + { + if ( best_cost < UINT32_MAX && max_iter == 0 ) { looping = false; } @@ -1209,7 +1301,14 @@ class ac_decomposition_impl /* limit */ if constexpr ( limit_iter ) { - if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + if ( limit <= 0 ) + { + looping = false; + } + } + if constexpr ( limit_sol ) + { + if ( best_cost < UINT32_MAX && max_iter == 0 ) { looping = false; } @@ -1226,7 +1325,14 @@ class ac_decomposition_impl /* limit */ if constexpr ( limit_iter ) { - if ( limit-- <= 0 || ( best_cost < UINT32_MAX && max_iter-- == 0 ) ) + if ( limit-- <= 0 ) + { + looping = false; + } + } + if constexpr ( limit_sol ) + { + if ( best_cost < UINT32_MAX && max_iter-- == 0 ) { looping = false; } @@ -1256,7 +1362,14 @@ class ac_decomposition_impl /* limit */ if constexpr ( limit_iter ) { - if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + if ( limit <= 0 ) + { + looping = false; + } + } + if constexpr ( limit_sol ) + { + if ( best_cost < UINT32_MAX && max_iter == 0 ) { looping = false; } @@ -1270,7 +1383,14 @@ class ac_decomposition_impl /* limit */ if constexpr ( limit_iter ) { - if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + if ( limit <= 0 ) + { + looping = false; + } + } + if constexpr ( limit_sol ) + { + if ( best_cost < UINT32_MAX && max_iter == 0 ) { looping = false; } @@ -1290,7 +1410,14 @@ class ac_decomposition_impl /* limit */ if constexpr ( limit_iter ) { - if ( limit <= 0 || ( best_cost < UINT32_MAX && max_iter == 0 ) ) + if ( limit <= 0 ) + { + looping = false; + } + } + if constexpr ( limit_sol ) + { + if ( best_cost < UINT32_MAX && max_iter == 0 ) { looping = false; } @@ -1307,7 +1434,14 @@ class ac_decomposition_impl /* limit */ if constexpr ( limit_iter ) { - if ( limit-- <= 0 || ( best_cost < UINT32_MAX && max_iter-- == 0 ) ) + if ( limit-- <= 0 ) + { + looping = false; + } + } + if constexpr ( limit_sol ) + { + if ( best_cost-- < UINT32_MAX && max_iter == 0 ) { looping = false; } @@ -1335,6 +1469,63 @@ class ac_decomposition_impl return res; } + std::array covering_solve_heuristic( std::vector& matrix ) + { + /* last value of res contains the size of the bound set */ + std::array res = { UINT32_MAX }; + uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; + uint64_t column = 0; + + uint32_t best = 0; + float best_cost = std::numeric_limits::max(); + for ( uint32_t i = 0; i < matrix.size(); ++i ) + { + if ( matrix[i].sort_cost < best_cost ) + { + best = i; + best_cost = matrix[i].sort_cost; + } + } + + /* select */ + column = matrix[best].column; + std::swap( matrix[0], matrix[best] ); + + /* get max number of BS's */ + uint32_t iter = 1; + + while ( iter < ps.lut_size - best_free_set && __builtin_popcountl( column ) != combinations ) + { + /* select column that minimizes the cost */ + best = 0; + best_cost = std::numeric_limits::max(); + for ( uint32_t i = iter; i < matrix.size(); ++i ) + { + float local_cost = ( (float) matrix[i].cost ) / __builtin_popcountl( matrix[i].column & ~column ); + if ( local_cost < best_cost ) + { + best = i; + best_cost = local_cost; + } + } + + column |= matrix[best].column; + std::swap( matrix[iter], matrix[best] ); + ++iter; + } + + if ( __builtin_popcountl( column ) != combinations ) + { + for ( uint32_t i = 0; i < iter; ++i ) + { + res[i] = i; + } + res[4] = iter; + } + + return res; + } + void adjust_truth_table_on_dc( STT& tt, STT& care, uint32_t var_index ) { assert( var_index < tt.num_vars() ); From dcc960bebad3253226dffb7b724d5ea5c076adc5 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Wed, 15 Nov 2023 21:57:29 +0100 Subject: [PATCH 36/67] Adding local search for covering --- src/acd/ac_decomposition.hpp | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 5a93c5f354..de409b649f 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -1079,6 +1079,9 @@ class ac_decomposition_impl return; } + /* improve solution with local search */ + covering_improve( matrix, solution ); + /* compute best bound sets */ uint32_t num_luts = 1 + solution[4]; uint32_t num_levels = 2; @@ -1526,6 +1529,51 @@ class ac_decomposition_impl return res; } + bool covering_improve( std::vector& matrix, std::array& solution ) + { + /* performs one iteration of local search */ + uint32_t best_cost = 0, local_cost = 0; + uint32_t num_elements = solution[4]; + uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; + bool improved = false; + + /* compute current cost */ + for ( uint32_t i = 0; i < num_elements; ++i ) + { + best_cost += matrix[solution[i]].cost; + } + + uint64_t column; + for ( uint32_t i = 0; i < num_elements; ++i ) + { + /* remove element i */ + local_cost = 0; + column = 0; + for ( uint32_t j = 0; j < num_elements; ++j ) + { + if ( j == i ) + continue; + local_cost += matrix[solution[j]].cost; + column |= matrix[solution[j]].column; + } + + /* search for a better replecemnts */ + for ( uint32_t j = 0; j < matrix.size(); ++j ) + { + if ( __builtin_popcount( column | matrix[j].column ) != combinations ) + continue; + if ( local_cost + matrix[j].cost < best_cost ) + { + solution[i] = j; + best_cost = local_cost + matrix[j].cost; + improved = true; + } + } + } + + return improved; + } + void adjust_truth_table_on_dc( STT& tt, STT& care, uint32_t var_index ) { assert( var_index < tt.num_vars() ); From b32bbdfef31bdfef9790823da480bc55d693a45f Mon Sep 17 00:00:00 2001 From: aletempiac Date: Thu, 16 Nov 2023 15:33:19 +0100 Subject: [PATCH 37/67] Improving set covering using unitary cost --- src/acd/ac_decomposition.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index de409b649f..193ef9698f 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -1080,7 +1080,8 @@ class ac_decomposition_impl } /* improve solution with local search */ - covering_improve( matrix, solution ); + while ( covering_improve( matrix, solution ) ) + ; /* compute best bound sets */ uint32_t num_luts = 1 + solution[4]; @@ -1202,7 +1203,7 @@ class ac_decomposition_impl float sort_cost = 0; if constexpr ( UseHeuristic ) { - sort_cost = ( (float) cost ) / ( __builtin_popcountl( column ) ); + sort_cost = 1.0f / ( __builtin_popcountl( column ) ); } else { @@ -1504,7 +1505,7 @@ class ac_decomposition_impl best_cost = std::numeric_limits::max(); for ( uint32_t i = iter; i < matrix.size(); ++i ) { - float local_cost = ( (float) matrix[i].cost ) / __builtin_popcountl( matrix[i].column & ~column ); + float local_cost = 1.0f / __builtin_popcountl( matrix[i].column & ~column ); if ( local_cost < best_cost ) { best = i; @@ -1517,7 +1518,7 @@ class ac_decomposition_impl ++iter; } - if ( __builtin_popcountl( column ) != combinations ) + if ( __builtin_popcountl( column ) == combinations ) { for ( uint32_t i = 0; i < iter; ++i ) { From 548fd6afb2d227df4eadf1c0d8d63ac350d0e9aa Mon Sep 17 00:00:00 2001 From: aletempiac Date: Thu, 16 Nov 2023 18:20:05 +0100 Subject: [PATCH 38/67] New version of enumeration of combinations --- src/acd/ac_decomposition.hpp | 224 +++++++++++------------------------ 1 file changed, 66 insertions(+), 158 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 193ef9698f..d59bf3d877 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -59,6 +59,9 @@ struct ac_decomposition_params /*! \brief Maximum number of iterations for covering. */ uint32_t max_iter{ 5000 }; + + /*! \brief Perform decomposition if support reducing. */ + bool support_reducing_only{ true }; }; /*! \brief Statistics for ac_decomposition */ @@ -88,7 +91,7 @@ class ac_decomposition_impl }; private: - static constexpr uint32_t max_num_vars = 8; + static constexpr uint32_t max_num_vars = 9; using STT = kitty::static_truth_table; public: @@ -126,17 +129,25 @@ class ac_decomposition_impl /* run ACD trying different bound sets and free sets */ uint32_t free_set_size = late_arriving; - uint32_t offset = std::max( static_cast( late_arriving ), 1u ); - for ( uint32_t i = offset; i <= ps.lut_size / 2 && i <= 3; ++i ) + uint32_t offset = static_cast( late_arriving ); + uint32_t start = std::max( offset, 1u ); + + /* perform only support reducing decomposition */ + if ( ps.support_reducing_only ) + { + start = std::max( start, num_vars - ps.lut_size ); + } + + for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= 3; ++i ) { /* TODO: add shared set */ auto evaluate_fn = [&]( STT const& tt ) { return column_multiplicity( tt, i ); }; - auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, evaluate_fn, false ); + auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, evaluate_fn ); - /* add cost if not support reducing */ + /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; /* check for feasible solution that improves the cost */ /* TODO: remove limit on cost */ - if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 12 ) + if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 10 ) { best_tt = tt_p; permutations = perm; @@ -458,8 +469,37 @@ class ac_decomposition_impl return std::make_tuple( best, res_perm, best_cost ); } + inline bool combinations_offset_next( uint32_t k, uint32_t offset, uint32_t *pComb, uint32_t *pInvPerm, STT& tt ) + { + uint32_t i; + + for ( i = k - 1; pComb[i] == num_vars - k + i; --i ) + { + if ( i == offset ) + return false; + } + + /* move vars */ + uint32_t var_old = pComb[i]; + uint32_t pos_new = pInvPerm[var_old + 1]; + std::swap( pInvPerm[var_old + 1], pInvPerm[var_old] ); + std::swap( pComb[i], pComb[pos_new] ); + kitty::swap_inplace( tt, i, pos_new ); + + for ( uint32_t j = i + 1; j < k; j++ ) + { + var_old = pComb[j]; + pos_new = pInvPerm[pComb[j - 1] + 1]; + std::swap( pInvPerm[pComb[j - 1] + 1], pInvPerm[var_old] ); + std::swap( pComb[j], pComb[pos_new] ); + kitty::swap_inplace( tt, j, pos_new ); + } + + return true; + } + template - std::tuple, uint32_t> enumerate_iset_combinations_offset( uint32_t free_set_size, uint32_t offset, Fn&& fn, bool verbose = false ) + std::tuple, uint32_t> enumerate_iset_combinations_offset( uint32_t free_set_size, uint32_t offset, Fn&& fn ) { STT tt = best_tt; @@ -467,178 +507,46 @@ class ac_decomposition_impl STT best_tt = tt; uint32_t best_cost = UINT32_MAX; - /* works up to 16 input truth tables */ - assert( num_vars <= 16 ); - - /* select k */ - free_set_size = std::min( free_set_size, num_vars - free_set_size ); + assert( free_set_size >= offset ); /* special case */ - if ( num_vars <= free_set_size || free_set_size <= offset ) + if ( free_set_size == offset ) { - if ( offset == free_set_size ) - { - best_cost = fn( tt ); - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << best_cost << " "; - print_perm( permutations.begin(), free_set_size ); - } - - return { tt, permutations, best_cost }; - } - else - { - return { tt, permutations, UINT32_MAX }; - } + best_cost = fn( tt ); + return { tt, permutations, best_cost }; } - /* decrease combinations */ - free_set_size -= offset; + /* works up to 16 input truth tables */ + assert( num_vars <= 16 ); - /* init permutation array */ - std::array perm, best_perm; - std::copy( permutations.begin(), permutations.begin() + num_vars, perm.begin() ); - best_perm = perm; + /* init combinations */ + uint32_t pComb[16], pInvPerm[16], bestPerm[16]; + for ( uint32_t i = 0; i < num_vars; ++i ) + { + pComb[i] = pInvPerm[i] = i; + } /* enumerate combinations */ - if ( free_set_size == 1 ) + do { uint32_t cost = fn( tt ); if ( cost < best_cost ) { best_tt = tt; best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size + offset ); - } - - for ( uint32_t i = offset + 1; i < num_vars; ++i ) - { - std::swap( perm[offset], perm[i] ); - kitty::swap_inplace( tt, offset, i ); - - uint32_t cost = fn( tt ); - if ( cost < best_cost ) + for ( uint32_t i = 0; i < num_vars; ++i ) { - best_tt = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size + offset ); + bestPerm[i] = pComb[i]; } } - } - else if ( free_set_size == 2 ) - { - for ( uint32_t i = 0; i < num_vars - 1 - offset; ++i ) - { - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best_tt = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size + offset ); - } - - for ( uint32_t j = offset + 2; j < num_vars - i; ++j ) - { - std::swap( perm[offset + 1], perm[j] ); - kitty::swap_inplace( tt, offset + 1, j ); - - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best_tt = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size + offset ); - } - } + } while( combinations_offset_next( free_set_size, offset, pComb, pInvPerm, tt ) ); - std::swap( perm[offset], perm[num_vars - i - 1] ); - kitty::swap_inplace( tt, offset, num_vars - i - 1 ); - } - } - else if ( free_set_size == 3 ) + std::vector res_perm( num_vars ); + for ( uint32_t i = 0; i < num_vars; ++i ) { - for ( uint32_t i = 0; i < num_vars - 2 - offset; ++i ) - { - for ( uint32_t j = i; j < num_vars - 2 - offset; ++j ) - { - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best_tt = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size + offset ); - } - - for ( uint32_t k = offset + 3; k < num_vars - j; ++k ) - { - std::swap( perm[offset + 2], perm[k] ); - kitty::swap_inplace( tt, offset + 2, k ); - - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best_tt = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size + offset ); - } - } - - std::swap( perm[offset + 1], perm[num_vars - j - 1] ); - kitty::swap_inplace( tt, offset + 1, num_vars - j - 1 ); - } - - std::swap( perm[offset], perm[num_vars - i - 1] ); - kitty::swap_inplace( tt, offset, num_vars - i - 1 ); - } + res_perm[i] = permutations[bestPerm[i]]; } - std::vector res_perm( num_vars ); - std::copy( best_perm.begin(), best_perm.begin() + num_vars, res_perm.begin() ); - return std::make_tuple( best_tt, res_perm, best_cost ); } From 8aa57c5d54bf7307c823d39fb9cc03a5e140dafb Mon Sep 17 00:00:00 2001 From: aletempiac Date: Thu, 16 Nov 2023 18:53:02 +0100 Subject: [PATCH 39/67] Decisions on late arrival --- src/acd/ac_decomposition.hpp | 46 +++++++++++++++++++++++++----------- src/acd/ac_wrapper.cpp | 3 ++- src/acd/ac_wrapper.h | 2 +- src/map/if/if.h | 2 +- src/map/if/ifDelay.c | 11 ++++----- 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index d59bf3d877..71caccff25 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -62,6 +62,9 @@ struct ac_decomposition_params /*! \brief Perform decomposition if support reducing. */ bool support_reducing_only{ true }; + + /*! \brief If decomposition with delay profile fails, ignore it. */ + bool try_no_late_arrival{ false }; }; /*! \brief Statistics for ac_decomposition */ @@ -157,28 +160,43 @@ class ac_decomposition_impl } } - if ( best_multiplicity == UINT32_MAX ) + if ( best_multiplicity == UINT32_MAX && ( !ps.try_no_late_arrival || late_arriving == 0 ) ) return -1; - /* compute isets */ - // std::vector isets = compute_isets( free_set_size ); + /* try without the delay profile */ + if ( best_multiplicity == UINT32_MAX && ps.try_no_late_arrival ) + { + if ( ps.support_reducing_only ) + { + start = std::max( 1u, num_vars - ps.lut_size ); + } - // generate_support_minimization_encodings(); - // solve_min_support_exact( isets, free_set_size ); + for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= 3; ++i ) + { + /* TODO: add shared set */ + auto evaluate_fn = [&]( STT const& tt ) { return column_multiplicity( tt, i ); }; + auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, 0, evaluate_fn ); + + /* additional cost if not support reducing */ + uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; + /* check for feasible solution that improves the cost */ /* TODO: remove limit on cost */ + if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 10 ) + { + best_tt = tt_p; + permutations = perm; + best_multiplicity = cost; + best_cost = cost + additional_cost; + free_set_size = i; + } + } + } - /* unfeasible decomposition */ - // if ( best_bound_sets.empty() ) - // { - // return -1; - // } + if ( best_multiplicity == UINT32_MAX ) + return -1; pst->num_luts = ps.lut_size - free_set_size; best_free_set = free_set_size; - /* TODO generate decomposition only when returning the result */ - // dec_result = generate_decomposition( free_set_size ); - - /* TODO: change return value */ return 0; } diff --git a/src/acd/ac_wrapper.cpp b/src/acd/ac_wrapper.cpp index aabe8e86fb..821ab3f982 100644 --- a/src/acd/ac_wrapper.cpp +++ b/src/acd/ac_wrapper.cpp @@ -4,7 +4,7 @@ // ABC_NAMESPACE_IMPL_START -int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost ) +int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ) { using namespace mockturtle; @@ -17,6 +17,7 @@ int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, ac_decomposition_params ps; ps.lut_size = lutSize; + ps.try_no_late_arrival = static_cast( try_no_late_arrival ); ac_decomposition_stats st; ac_decomposition_impl acd( tt, nVars, ps, &st ); diff --git a/src/acd/ac_wrapper.h b/src/acd/ac_wrapper.h index cb22acf801..5e0af37877 100644 --- a/src/acd/ac_wrapper.h +++ b/src/acd/ac_wrapper.h @@ -12,7 +12,7 @@ extern "C" { #endif -int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost ); +int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ); int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ); #ifdef __cplusplus diff --git a/src/map/if/if.h b/src/map/if/if.h index 56f0bb7edf..05dc339492 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -700,7 +700,7 @@ extern int If_ManCountSpecialPos( If_Man_t * p ); extern void If_CutTraverse( If_Man_t * p, If_Obj_t * pRoot, If_Cut_t * pCut, Vec_Ptr_t * vNodes ); extern void If_ObjPrint( If_Obj_t * pObj ); -extern int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost ); +extern int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ); extern int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ); ABC_NAMESPACE_HEADER_END diff --git a/src/map/if/ifDelay.c b/src/map/if/ifDelay.c index fcd53e3485..c1ecd7c08b 100644 --- a/src/map/if/ifDelay.c +++ b/src/map/if/ifDelay.c @@ -471,12 +471,13 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay ) } /* remove from critical set */ - if ( !use_late_arrival ) + if ( !use_late_arrival && nLeafMax > LutSize / 2 ) + { uLeafMask = 0; + } - word *pTruth = If_CutTruthW( p, pCut ); - int val = acd_evaluate( pTruth, pCut->nLeaves, LutSize, &uLeafMask, &cost ); + int val = acd_evaluate( pTruth, pCut->nLeaves, LutSize, &uLeafMask, &cost, !use_late_arrival ); /* not feasible decomposition */ pCut->acdDelay = uLeafMask; @@ -507,10 +508,8 @@ int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ) } // int LutSize = p->pPars->pLutStruct[0] - '0'; - int LutSize = 6; int i, leaf_delay; - int DelayMax = -1, nLeafMax = 0; - unsigned uLeafMask = 0; + int DelayMax = -1; for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) { leaf_delay = If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay; From b77bdeeb173ef7799dc7a2b406ef7f1155ae3b5a Mon Sep 17 00:00:00 2001 From: aletempiac Date: Thu, 16 Nov 2023 19:21:29 +0100 Subject: [PATCH 40/67] Enabling ACD for area --- src/map/if/if.h | 2 +- src/map/if/ifDelay.c | 36 +++++++++++++++++++++++++----------- src/map/if/ifMap.c | 2 +- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/map/if/if.h b/src/map/if/if.h index 05dc339492..b4d06edca6 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -570,7 +570,7 @@ extern int If_CutSopBalancePinDelaysInt( Vec_Int_t * vCover, int * p extern int If_CutSopBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); extern int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ); extern int If_CutLutBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); -extern int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay ); +extern int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ); extern int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ); extern float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required ); /*=== ifDsd.c =============================================================*/ diff --git a/src/map/if/ifDelay.c b/src/map/if/ifDelay.c index c1ecd7c08b..75a0a0a668 100644 --- a/src/map/if/ifDelay.c +++ b/src/map/if/ifDelay.c @@ -412,7 +412,7 @@ int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ) } } -int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay ) +int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ) { pCut->fUser = 1; pCut->Cost = pCut->nLeaves > 1 ? 1 : 0; @@ -460,20 +460,34 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, int best_delay ) // } /* compute the decomposition */ - int use_late_arrival = DelayMax + 2 >= best_delay; + int use_late_arrival; unsigned cost = 1; - - /* TODO: have checks based on delay */ - if ( use_late_arrival && nLeafMax > LutSize / 2 ) + + if ( optDelay ) { - pCut->Cost = IF_COST_MAX; - return ABC_INFINITY; + /* checks based on delay: must be better than the previous best cut */ + use_late_arrival = DelayMax + 2 >= If_ObjCutBest(pObj)->Delay; + } + else + { + /* checks based on delay: look at the required time */ + use_late_arrival = DelayMax + 2 > pObj->Required + p->fEpsilon; } - - /* remove from critical set */ - if ( !use_late_arrival && nLeafMax > LutSize / 2 ) + + /* Too many late-arriving signals */ + if ( nLeafMax > LutSize / 2 ) { - uLeafMask = 0; + if ( use_late_arrival ) + { + /* unfeasible decomposition */ + pCut->Cost = IF_COST_MAX; + return ABC_INFINITY; + } + else + { + /* remove critical signals as not needed */ + uLeafMask = 0; + } } word *pTruth = If_CutTruthW( p, pCut ); diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index da83b5525c..1455846f6e 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -431,7 +431,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); else if ( p->pPars->fAcd ) { - pCut->Delay = If_AcdEval( p, pCut, fFirst ? ABC_INFINITY : (int) If_ObjCutBest(pObj)->Delay ); + pCut->Delay = If_AcdEval( p, pCut, pObj, Mode == 0 ); pCut->fUseless = pCut->Delay == ABC_INFINITY; } else if ( p->pPars->fUserSesLib ) From 1ca7a3a353dfce495a71d2f9d7abf3b3ffdddd71 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Fri, 17 Nov 2023 15:49:29 +0100 Subject: [PATCH 41/67] Remove symmetries in covering table --- src/acd/ac_decomposition.hpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 71caccff25..0faf46b917 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -150,7 +150,7 @@ class ac_decomposition_impl /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; /* check for feasible solution that improves the cost */ /* TODO: remove limit on cost */ - if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 10 ) + if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 12 ) { best_tt = tt_p; permutations = perm; @@ -194,7 +194,7 @@ class ac_decomposition_impl if ( best_multiplicity == UINT32_MAX ) return -1; - pst->num_luts = ps.lut_size - free_set_size; + pst->num_luts = best_multiplicity <= 2 ? 2 : best_multiplicity <= 4 ? 3 : best_multiplicity <= 8 ? 4 : 5; best_free_set = free_set_size; return 0; @@ -845,10 +845,10 @@ class ac_decomposition_impl void generate_support_minimization_encodings() { uint32_t count = 0; - uint32_t num_combs_exact[4] = { 2, 6, 70, 12870 }; + uint32_t num_combs_exact[4] = { 1, 3, 35, 6435 }; /* enable don't cares only if not a power of 2 */ - uint32_t num_combs = 3; + uint32_t num_combs = 2; if ( __builtin_popcount( best_multiplicity ) == 1 ) { for ( uint32_t i = 0; i < 4; ++i ) @@ -913,6 +913,12 @@ class ac_decomposition_impl generate_support_minimization_encodings_rec( onset, offset, var + 1, count ); onset &= ~( 1 << var ); + /* remove symmetries */ + if ( var == 0 ) + { + return; + } + /* move var in OFFSET */ offset |= 1 << var; generate_support_minimization_encodings_rec( onset, offset, var + 1, count ); @@ -1181,7 +1187,12 @@ class ac_decomposition_impl assert( best_multiplicity <= 16 ); /* determine the number of needed loops*/ - if ( best_multiplicity <= 4 ) + if ( best_multiplicity <= 2 ) + { + res[4] = 1; + res[0] = 0; + } + else if ( best_multiplicity <= 4 ) { res[4] = 2; for ( uint32_t i = 0; i < matrix.size() - 1; ++i ) From 3d602e2f00fb2fa1ea06f61c6ff1e0391232d439 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Fri, 17 Nov 2023 15:55:10 +0100 Subject: [PATCH 42/67] Adding sorting of columns in heuristic covering --- src/acd/ac_decomposition.hpp | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 0faf46b917..9fb17c7647 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -997,7 +997,7 @@ class ac_decomposition_impl best_bound_sets.clear(); /* create covering matrix */ - if ( !create_covering_matrix( isets, matrix, free_set_size, false ) ) + if ( !create_covering_matrix( isets, matrix, free_set_size, true ) ) { return; } @@ -1148,29 +1148,24 @@ class ac_decomposition_impl sol_existance |= column; } - /* necessary condition for the existance of a solution */ - // if ( __builtin_popcountl( sol_existance ) != combinations ) - // { - // return false; - // } - if ( !sort ) { return true; } - std::sort( matrix.begin(), matrix.end(), [&]( auto const& a, auto const& b ) { - return a.sort_cost < b.sort_cost; - } ); - - /* print */ - // if ( best_multiplicity < 6 ) - // { - // for ( uint32_t i = 0; i < columns.size(); ++i ) - // { - // std::cout << indexes[i] << " " << costs[i] << " \t" << columns[i] << "\n"; - // } - // } + if constexpr ( UseHeuristic ) + { + std::sort( matrix.begin(), matrix.end(), [&]( auto const& a, auto const& b ) { + return a.cost < b.cost; + } ); + return true; + } + else + { + std::sort( matrix.begin(), matrix.end(), [&]( auto const& a, auto const& b ) { + return a.sort_cost < b.sort_cost; + } ); + } return true; } From 1d7dfd25c6d346e5e0849b8084250a1596160e38 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Fri, 17 Nov 2023 16:58:17 +0100 Subject: [PATCH 43/67] Improving ACD mapping --- src/acd/ac_decomposition.hpp | 4 +++- src/acd/ac_wrapper.cpp | 3 +-- src/base/abci/abcIf.c | 26 -------------------------- src/map/if/if.h | 2 +- src/map/if/ifCore.c | 25 ++++++++++++++++++------- src/map/if/ifDelay.c | 31 +++++++++++++++---------------- src/map/if/ifMap.c | 2 +- 7 files changed, 39 insertions(+), 54 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 9fb17c7647..bfcbf06e1b 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -166,6 +166,7 @@ class ac_decomposition_impl /* try without the delay profile */ if ( best_multiplicity == UINT32_MAX && ps.try_no_late_arrival ) { + delay_profile = 0; if ( ps.support_reducing_only ) { start = std::max( 1u, num_vars - ps.lut_size ); @@ -197,7 +198,8 @@ class ac_decomposition_impl pst->num_luts = best_multiplicity <= 2 ? 2 : best_multiplicity <= 4 ? 3 : best_multiplicity <= 8 ? 4 : 5; best_free_set = free_set_size; - return 0; + /* return number of levels */ + return delay_profile == 0 ? 2 : 1; } int compute_decomposition() diff --git a/src/acd/ac_wrapper.cpp b/src/acd/ac_wrapper.cpp index 821ab3f982..6bb41ca377 100644 --- a/src/acd/ac_wrapper.cpp +++ b/src/acd/ac_wrapper.cpp @@ -22,7 +22,6 @@ int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, ac_decomposition_impl acd( tt, nVars, ps, &st ); int val = acd.run( *pdelay ); - // int val = acd.compute_decomposition(); if ( val < 0 ) { @@ -33,7 +32,7 @@ int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, *pdelay = acd.get_profile(); *cost = st.num_luts; - return 0; + return val; } int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ) diff --git a/src/base/abci/abcIf.c b/src/base/abci/abcIf.c index 079cd0066a..b7d7962739 100644 --- a/src/base/abci/abcIf.c +++ b/src/base/abci/abcIf.c @@ -458,34 +458,10 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC // get the delay profile unsigned delayProfile = pCutBest->acdDelay; - // If_Obj_t * pLeaf; - // int i, leafDelay; - // int DelayMax = -1, nLeafMax = 0; - // unsigned uLeafMask = 0; - - // If_CutForEachLeaf( pIfMan, pCutBest, pLeaf, i ) - // { - // leafDelay = If_ObjCutBest(pLeaf)->Delay; - - // if ( DelayMax < leafDelay ) - // { - // DelayMax = leafDelay; - // nLeafMax = 1; - // uLeafMask = (1 << i); - // } - // else if ( DelayMax == leafDelay ) - // { - // nLeafMax++; - // uLeafMask |= (1 << i); - // } - // } - // perform LUT-decomposition and return the LUT-structure unsigned char decompArray[92]; int val = acd_decompose( pTruth, pCutBest->nLeaves, 6, &(delayProfile), decompArray ); - assert( val == 0 ); - // assert( DelayMax + 2 >= pCutBest->Delay ); // convert the LUT-structure into a set of logic nodes in Abc_Ntk_t unsigned char bytes_check = decompArray[0]; @@ -561,8 +537,6 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC /* check correct read */ assert( byte_p == decompArray[0] ); - - // this is a placeholder, which takes the truth table and converts it into an AIG without LUT-decomposition } /**Function************************************************************* diff --git a/src/map/if/if.h b/src/map/if/if.h index b4d06edca6..c3ba59be43 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -570,7 +570,7 @@ extern int If_CutSopBalancePinDelaysInt( Vec_Int_t * vCover, int * p extern int If_CutSopBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); extern int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ); extern int If_CutLutBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); -extern int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ); +extern int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, int fFirst ); extern int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ); extern float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required ); /*=== ifDsd.c =============================================================*/ diff --git a/src/map/if/ifCore.c b/src/map/if/ifCore.c index a8e482912d..ad3c85179e 100644 --- a/src/map/if/ifCore.c +++ b/src/map/if/ifCore.c @@ -128,16 +128,11 @@ int If_ManPerformMappingComb( If_Man_t * p ) if ( p->pPars->fPreprocess && !p->pPars->fArea ) { // map for delay - If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 1, "Delay" ); - if ( p->pPars->fAcd ) - { - // p->pPars->nLutSize = oldLutSize; p->useLimitAdc = 0; - If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 0, "Delay" ); + If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 1, "Delay" ); + if ( p->pPars->fAcd ) p->useLimitAdc = 1; - // p->pPars->nLutSize = 6; - } // map for delay second option p->pPars->fFancy = 1; @@ -160,17 +155,33 @@ int If_ManPerformMappingComb( If_Man_t * p ) // area flow oriented mapping for ( i = 0; i < p->pPars->nFlowIters; i++ ) { + // if ( p->pPars->fAcd && i == 0 ) + // { + // p->useLimitAdc = 0; + // } If_ManPerformMappingRound( p, p->pPars->nCutsMax, 1, 0, 0, "Flow" ); if ( p->pPars->fExpRed ) If_ManImproveMapping( p ); + // if ( p->pPars->fAcd && i == 0 ) + // { + // p->useLimitAdc = 1; + // } } // area oriented mapping for ( i = 0; i < p->pPars->nAreaIters; i++ ) { + // if ( p->pPars->fAcd && i == 0 ) + // { + // p->useLimitAdc = 0; + // } If_ManPerformMappingRound( p, p->pPars->nCutsMax, 2, 0, 0, "Area" ); if ( p->pPars->fExpRed ) If_ManImproveMapping( p ); + // if ( p->pPars->fAcd && i == 0 ) + // { + // p->useLimitAdc = 1; + // } } if ( p->pPars->fVerbose ) diff --git a/src/map/if/ifDelay.c b/src/map/if/ifDelay.c index 75a0a0a668..90fab6b006 100644 --- a/src/map/if/ifDelay.c +++ b/src/map/if/ifDelay.c @@ -412,7 +412,7 @@ int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ) } } -int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ) +int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, int fFirst ) { pCut->fUser = 1; pCut->Cost = pCut->nLeaves > 1 ? 1 : 0; @@ -428,7 +428,6 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ) return (int)If_ObjCutBest(If_CutLeaf(p, pCut, 0))->Delay; } - // int LutSize = p->pPars->pLutStruct[0] - '0'; int LutSize = 6; int i, leaf_delay; int DelayMax = -1, nLeafMax = 0; @@ -454,24 +453,23 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ) pCut->acdDelay = ( 1 << LutSize ) - 1; return DelayMax + 1; } - // else if ( DelayMax + 1 >= best_delay ) - // { - // return DelayMax + 2; - // } /* compute the decomposition */ - int use_late_arrival; + int use_late_arrival = 0; unsigned cost = 1; - if ( optDelay ) + if ( !fFirst ) { - /* checks based on delay: must be better than the previous best cut */ - use_late_arrival = DelayMax + 2 >= If_ObjCutBest(pObj)->Delay; - } - else - { - /* checks based on delay: look at the required time */ - use_late_arrival = DelayMax + 2 > pObj->Required + p->fEpsilon; + if ( optDelay ) + { + /* checks based on delay: must be better than the previous best cut */ + use_late_arrival = DelayMax + 2 >= If_ObjCutBest(pObj)->Delay; + } + else + { + /* checks based on delay: look at the required time */ + use_late_arrival = DelayMax + 2 > pObj->Required + p->fEpsilon; + } } /* Too many late-arriving signals */ @@ -490,6 +488,7 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ) } } + /* returns the delay of the decomposition */ word *pTruth = If_CutTruthW( p, pCut ); int val = acd_evaluate( pTruth, pCut->nLeaves, LutSize, &uLeafMask, &cost, !use_late_arrival ); @@ -503,7 +502,7 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay ) pCut->Cost = cost; - return DelayMax + ( use_late_arrival ? 1 : 2 ); + return DelayMax + val; } int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ) diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index 1455846f6e..69f2ead81a 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -431,7 +431,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); else if ( p->pPars->fAcd ) { - pCut->Delay = If_AcdEval( p, pCut, pObj, Mode == 0 ); + pCut->Delay = If_AcdEval( p, pCut, pObj, Mode == 0, fFirst ); pCut->fUseless = pCut->Delay == ABC_INFINITY; } else if ( p->pPars->fUserSesLib ) From f7a520b9571aab110781b9fdf4093da60fe16b6d Mon Sep 17 00:00:00 2001 From: aletempiac Date: Sun, 19 Nov 2023 18:51:50 +0100 Subject: [PATCH 44/67] restructuring code --- src/acd/ac_decomposition.hpp | 125 +++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 41 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index bfcbf06e1b..c9b1b2453a 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "kitty_constants.hpp" @@ -141,11 +142,16 @@ class ac_decomposition_impl start = std::max( start, num_vars - ps.lut_size ); } + std::function column_multiplicity_fn[3] = { + [this]( STT const& tt ) { return column_multiplicity<1u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity<2u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity<3u>( tt ); } + }; + for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= 3; ++i ) { /* TODO: add shared set */ - auto evaluate_fn = [&]( STT const& tt ) { return column_multiplicity( tt, i ); }; - auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, evaluate_fn ); + auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, column_multiplicity_fn[i - 1] ); /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; @@ -175,8 +181,7 @@ class ac_decomposition_impl for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= 3; ++i ) { /* TODO: add shared set */ - auto evaluate_fn = [&]( STT const& tt ) { return column_multiplicity( tt, i ); }; - auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, 0, evaluate_fn ); + auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, 0, column_multiplicity_fn[i - 1] ); /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; @@ -262,59 +267,33 @@ class ac_decomposition_impl } private: - uint32_t column_multiplicity( STT tt, uint32_t free_set_size ) + template + uint32_t column_multiplicity( STT tt ) { uint64_t multiplicity_set[4] = { 0u, 0u, 0u, 0u }; uint32_t multiplicity = 0; uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + uint64_t constexpr masks_bits[] = { 0x0, 0x3, 0xF, 0x3F }; + uint64_t constexpr masks_idx[] = { 0x0, 0x0, 0x0, 0x3 }; /* supports up to 64 values of free set (256 for |FS| == 3)*/ assert( free_set_size <= 3 ); /* extract iset functions */ - if ( free_set_size == 1 ) - { - auto it = std::begin( tt ); - for ( auto i = 0u; i < num_blocks; ++i ) - { - for ( auto j = 0; j < 32; ++j ) - { - multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0x3 ); - *it >>= 2; - } - ++it; - } - } - else if ( free_set_size == 2 ) - { - auto it = std::begin( tt ); - for ( auto i = 0u; i < num_blocks; ++i ) - { - for ( auto j = 0; j < 16; ++j ) - { - multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0xF ); - *it >>= 4; - } - ++it; - } - } - else /* free set size 3 */ + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) { - auto it = std::begin( tt ); - for ( auto i = 0u; i < num_blocks; ++i ) + for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) { - for ( auto j = 0; j < 8; ++j ) - { - multiplicity_set[( *it >> 6 ) & 0x3] |= UINT64_C( 1 ) << ( *it & 0x3F ); - *it >>= 8; - } - ++it; + multiplicity_set[( *it >> 6 ) & masks_idx[free_set_size]] |= UINT64_C( 1 ) << ( *it & masks_bits[free_set_size] ); + *it >>= ( 1u << free_set_size ); } + ++it; } multiplicity = __builtin_popcountl( multiplicity_set[0] ); - if ( free_set_size == 3 ) + if constexpr ( free_set_size == 3 ) { multiplicity += __builtin_popcountl( multiplicity_set[1] ); multiplicity += __builtin_popcountl( multiplicity_set[2] ); @@ -324,6 +303,70 @@ class ac_decomposition_impl return multiplicity; } + // uint32_t column_multiplicity2( STT tt, uint32_t free_set_size ) + // { + // uint64_t multiplicity_set[4] = { 0u, 0u, 0u, 0u }; + // uint32_t multiplicity = 0; + // uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + + // /* supports up to 64 values of free set (256 for |FS| == 3)*/ + // assert( free_set_size <= 5 ); + + // std::unordered_set column_to_iset; + + // /* extract iset functions */ + // if ( free_set_size == 1 ) + // { + // auto it = std::begin( tt ); + // for ( auto i = 0u; i < num_blocks; ++i ) + // { + // for ( auto j = 0; j < 32; ++j ) + // { + // multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0x3 ); + // *it >>= 2; + // } + // ++it; + // } + // } + // else if ( free_set_size == 2 ) + // { + // auto it = std::begin( tt ); + // for ( auto i = 0u; i < num_blocks; ++i ) + // { + // for ( auto j = 0; j < 16; ++j ) + // { + // multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0xF ); + // *it >>= 4; + // } + // ++it; + // } + // } + // else /* free set size 3 */ + // { + // auto it = std::begin( tt ); + // for ( auto i = 0u; i < num_blocks; ++i ) + // { + // for ( auto j = 0; j < 8; ++j ) + // { + // multiplicity_set[( *it >> 6 ) & 0x3] |= UINT64_C( 1 ) << ( *it & 0x3F ); + // *it >>= 8; + // } + // ++it; + // } + // } + + // multiplicity = __builtin_popcountl( multiplicity_set[0] ); + + // if ( free_set_size == 3 ) + // { + // multiplicity += __builtin_popcountl( multiplicity_set[1] ); + // multiplicity += __builtin_popcountl( multiplicity_set[2] ); + // multiplicity += __builtin_popcountl( multiplicity_set[3] ); + // } + + // return multiplicity; + // } + template std::tuple, uint32_t> enumerate_iset_combinations( uint32_t free_set_size, Fn&& fn, bool verbose = false ) { From 672fd1b629ede5d67484f73ca9f0f1830fd92322 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Sun, 19 Nov 2023 18:53:54 +0100 Subject: [PATCH 45/67] removing not used methods --- src/acd/ac_decomposition.hpp | 165 ----------------------------------- 1 file changed, 165 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index c9b1b2453a..2714f7a8e7 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -367,171 +367,6 @@ class ac_decomposition_impl // return multiplicity; // } - template - std::tuple, uint32_t> enumerate_iset_combinations( uint32_t free_set_size, Fn&& fn, bool verbose = false ) - { - /* works up to 16 input truth tables */ - assert( num_vars <= 16 ); - - /* special case */ - STT tt = best_tt; - if ( num_vars <= free_set_size || free_set_size == 0 ) - { - return { tt, permutations, UINT32_MAX }; - } - - /* select k */ - // free_set_size = std::min( free_set_size, num_vars - free_set_size ); - - /* init permutation array */ - std::array perm, best_perm; - std::copy( permutations.begin(), permutations.begin() + num_vars, perm.begin() ); - best_perm = perm; - - /* TT with best cost */ - STT best = tt; - uint32_t best_cost = UINT32_MAX; - - /* enumerate combinations */ - if ( free_set_size == 1 ) - { - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size ); - } - - for ( uint32_t i = 1; i < num_vars; ++i ) - { - std::swap( perm[0], perm[i] ); - kitty::swap_inplace( tt, 0, i ); - - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size ); - } - } - } - else if ( free_set_size == 2 ) - { - for ( uint32_t i = 0; i < num_vars - 1; ++i ) - { - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size ); - } - - for ( uint32_t j = 2; j < num_vars - i; ++j ) - { - std::swap( perm[1], perm[j] ); - kitty::swap_inplace( tt, 1, j ); - - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size ); - } - } - - std::swap( perm[0], perm[num_vars - i - 1] ); - kitty::swap_inplace( tt, 0, num_vars - i - 1 ); - } - } - else if ( free_set_size == 3 ) - { - for ( uint32_t i = 0; i < num_vars - 2; ++i ) - { - for ( uint32_t j = i; j < num_vars - 2; ++j ) - { - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size ); - } - - for ( uint32_t k = 3; k < num_vars - j; ++k ) - { - std::swap( perm[2], perm[k] ); - kitty::swap_inplace( tt, 2, k ); - - uint32_t cost = fn( tt ); - if ( cost < best_cost ) - { - best = tt; - best_cost = cost; - best_perm = perm; - } - - if ( verbose ) - { - kitty::print_hex( tt ); - std::cout << " " << cost << " "; - print_perm( perm.begin(), free_set_size ); - } - } - - std::swap( perm[1], perm[num_vars - j - 1] ); - kitty::swap_inplace( tt, 1, num_vars - j - 1 ); - } - - std::swap( perm[0], perm[num_vars - i - 1] ); - kitty::swap_inplace( tt, 0, num_vars - i - 1 ); - } - } - - std::vector res_perm( num_vars ); - std::copy( best_perm.begin(), best_perm.begin() + num_vars, res_perm.begin() ); - - return std::make_tuple( best, res_perm, best_cost ); - } - inline bool combinations_offset_next( uint32_t k, uint32_t offset, uint32_t *pComb, uint32_t *pInvPerm, STT& tt ) { uint32_t i; From 219d6d86d6dd2e6115048d5266a8da008ac57fd9 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Sun, 19 Nov 2023 19:33:19 +0100 Subject: [PATCH 46/67] Simplifying code --- src/acd/ac_decomposition.hpp | 204 ++++++++++++----------------------- 1 file changed, 69 insertions(+), 135 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 2714f7a8e7..6a7a90a8d4 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -88,7 +88,7 @@ class ac_decomposition_impl private: struct encoding_matrix { - uint64_t column{ 0 }; + uint64_t column; uint32_t cost{ 0 }; uint32_t index{ 0 }; float sort_cost{ 0 }; @@ -142,10 +142,12 @@ class ac_decomposition_impl start = std::max( start, num_vars - ps.lut_size ); } - std::function column_multiplicity_fn[3] = { + std::function column_multiplicity_fn[5] = { [this]( STT const& tt ) { return column_multiplicity<1u>( tt ); }, [this]( STT const& tt ) { return column_multiplicity<2u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity<3u>( tt ); } + [this]( STT const& tt ) { return column_multiplicity<3u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity4<4u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } }; for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= 3; ++i ) @@ -277,7 +279,7 @@ class ac_decomposition_impl uint64_t constexpr masks_idx[] = { 0x0, 0x0, 0x0, 0x3 }; /* supports up to 64 values of free set (256 for |FS| == 3)*/ - assert( free_set_size <= 3 ); + static_assert( free_set_size <= 3 ); /* extract iset functions */ auto it = std::begin( tt ); @@ -303,69 +305,55 @@ class ac_decomposition_impl return multiplicity; } - // uint32_t column_multiplicity2( STT tt, uint32_t free_set_size ) - // { - // uint64_t multiplicity_set[4] = { 0u, 0u, 0u, 0u }; - // uint32_t multiplicity = 0; - // uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; - - // /* supports up to 64 values of free set (256 for |FS| == 3)*/ - // assert( free_set_size <= 5 ); - - // std::unordered_set column_to_iset; - - // /* extract iset functions */ - // if ( free_set_size == 1 ) - // { - // auto it = std::begin( tt ); - // for ( auto i = 0u; i < num_blocks; ++i ) - // { - // for ( auto j = 0; j < 32; ++j ) - // { - // multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0x3 ); - // *it >>= 2; - // } - // ++it; - // } - // } - // else if ( free_set_size == 2 ) - // { - // auto it = std::begin( tt ); - // for ( auto i = 0u; i < num_blocks; ++i ) - // { - // for ( auto j = 0; j < 16; ++j ) - // { - // multiplicity_set[0] |= UINT64_C( 1 ) << ( *it & 0xF ); - // *it >>= 4; - // } - // ++it; - // } - // } - // else /* free set size 3 */ - // { - // auto it = std::begin( tt ); - // for ( auto i = 0u; i < num_blocks; ++i ) - // { - // for ( auto j = 0; j < 8; ++j ) - // { - // multiplicity_set[( *it >> 6 ) & 0x3] |= UINT64_C( 1 ) << ( *it & 0x3F ); - // *it >>= 8; - // } - // ++it; - // } - // } - - // multiplicity = __builtin_popcountl( multiplicity_set[0] ); - - // if ( free_set_size == 3 ) - // { - // multiplicity += __builtin_popcountl( multiplicity_set[1] ); - // multiplicity += __builtin_popcountl( multiplicity_set[2] ); - // multiplicity += __builtin_popcountl( multiplicity_set[3] ); - // } - - // return multiplicity; - // } + template + uint32_t column_multiplicity4( STT tt ) + { + unsigned char multiplicity_set[1 << 16] = { 0 }; + uint32_t multiplicity = 0; + uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + uint64_t constexpr masks[] = { 0x0, 0x3, 0xF, 0xFF, 0xFFFF }; + + static_assert( free_set_size <= 4 ); + + /* extract iset functions */ + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) + { + multiplicity += multiplicity_set[*it & masks[free_set_size]]++ == 0 ? 1 : 0; + *it >>= ( 1u << free_set_size ); + } + ++it; + } + + return multiplicity; + } + + template + uint32_t column_multiplicity5( STT tt ) + { + uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + uint64_t constexpr masks[] = { 0x0, 0x3, 0xF, 0xFF, 0xFFFF, 0xFFFFFFFF }; + + std::unordered_set multiplicity_set; + + static_assert( free_set_size <= 5 ); + + /* extract iset functions */ + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) + { + for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) + { + multiplicity_set.insert( *it & masks[free_set_size] ); + *it >>= ( 1u << free_set_size ); + } + ++it; + } + + return static_cast( multiplicity_set.size() ); + } inline bool combinations_offset_next( uint32_t k, uint32_t offset, uint32_t *pComb, uint32_t *pInvPerm, STT& tt ) { @@ -459,84 +447,30 @@ class ac_decomposition_impl STT tt = best_tt; uint32_t offset = 0; uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + uint64_t constexpr masks[] = { 0x0, 0x3, 0xF, 0xFF, 0xFFFF, 0xFFFFFFFF }; - if ( free_set_size == 1 ) + auto it = std::begin( tt ); + for ( auto i = 0u; i < num_blocks; ++i ) { - auto it = std::begin( tt ); - for ( auto i = 0u; i < num_blocks; ++i ) + for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) { - for ( auto j = 0; j < 32; ++j ) - { - uint64_t val = *it & 0x3; + uint64_t val = *it & masks[free_set_size]; - if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) - { - isets[el->second]._bits[i / 2] |= UINT64_C( 1 ) << ( j + offset ); - } - else - { - isets[column_to_iset.size()]._bits[i / 2] |= UINT64_C( 1 ) << ( j + offset ); - column_to_iset[val] = column_to_iset.size(); - } - - *it >>= 2; - } - - offset ^= 32; - ++it; - } - } - else if ( free_set_size == 2 ) - { - auto it = std::begin( tt ); - for ( auto i = 0u; i < num_blocks; ++i ) - { - for ( auto j = 0; j < 16; ++j ) + if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) { - uint64_t val = *it & 0xF; - - if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) - { - isets[el->second]._bits[i / 4] |= UINT64_C( 1 ) << ( j + offset ); - } - else - { - isets[column_to_iset.size()]._bits[i / 4] |= UINT64_C( 1 ) << ( j + offset ); - column_to_iset[val] = column_to_iset.size(); - } - - *it >>= 4; + isets[el->second]._bits[i / ( 1u << free_set_size )] |= UINT64_C( 1 ) << ( j + offset ); } - - offset = ( offset + 16 ) % 64; - ++it; - } - } - else /* free set size 3 */ - { - auto it = std::begin( tt ); - for ( auto i = 0u; i < num_blocks; ++i ) - { - for ( auto j = 0; j < 8; ++j ) + else { - uint64_t val = *it & 0xFF; - - if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) - { - isets[el->second]._bits[i / 8] |= UINT64_C( 1 ) << ( j + offset ); - } - else - { - isets[column_to_iset.size()]._bits[i / 8] |= UINT64_C( 1 ) << ( j + offset ); - column_to_iset[val] = column_to_iset.size(); - } - - *it >>= 8; + isets[column_to_iset.size()]._bits[i / ( 1u << free_set_size )] |= UINT64_C( 1 ) << ( j + offset ); + column_to_iset[val] = column_to_iset.size(); } - offset = ( offset + 8 ) % 64; - ++it; + *it >>= ( 1u << free_set_size ); } + + offset = ( offset + ( 64 >> free_set_size ) ) % 64; + ++it; } /* extend isets to cover the whole truth table */ From d10d450f38fa1a4e01b4343fd5afba006aea5963 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Sun, 19 Nov 2023 21:59:40 +0100 Subject: [PATCH 47/67] Final implementation --- src/acd/ac_decomposition.hpp | 77 ++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 6a7a90a8d4..0a05552e2d 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -58,6 +58,9 @@ struct ac_decomposition_params /*! \brief LUT size for decomposition. */ uint32_t lut_size{ 6 }; + /*! \brief Perform decomposition if support reducing. */ + uint32_t max_free_set_vars{ 4 }; + /*! \brief Maximum number of iterations for covering. */ uint32_t max_iter{ 5000 }; @@ -88,14 +91,14 @@ class ac_decomposition_impl private: struct encoding_matrix { - uint64_t column; + uint64_t column[2]; uint32_t cost{ 0 }; uint32_t index{ 0 }; float sort_cost{ 0 }; }; private: - static constexpr uint32_t max_num_vars = 9; + static constexpr uint32_t max_num_vars = 10; using STT = kitty::static_truth_table; public: @@ -118,7 +121,7 @@ class ac_decomposition_impl uint32_t late_arriving = __builtin_popcount( delay_profile ); /* return a high cost if too many late arriving variables */ - if ( late_arriving > ps.lut_size / 2 || late_arriving > 3 ) + if ( late_arriving > ps.lut_size - 1 || late_arriving > ps.max_free_set_vars ) { return -1; } @@ -150,15 +153,15 @@ class ac_decomposition_impl [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } }; - for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= 3; ++i ) + for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i ) { /* TODO: add shared set */ auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, column_multiplicity_fn[i - 1] ); /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; - /* check for feasible solution that improves the cost */ /* TODO: remove limit on cost */ - if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 12 ) + /* check for feasible solution that improves the cost */ + if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost <= 16 ) { best_tt = tt_p; permutations = perm; @@ -180,15 +183,15 @@ class ac_decomposition_impl start = std::max( 1u, num_vars - ps.lut_size ); } - for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= 3; ++i ) + for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i ) { /* TODO: add shared set */ auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, 0, column_multiplicity_fn[i - 1] ); /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; - /* check for feasible solution that improves the cost */ /* TODO: remove limit on cost */ - if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost < 10 ) + /* check for feasible solution that improves the cost */ + if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost <= 16 ) { best_tt = tt_p; permutations = perm; @@ -220,7 +223,7 @@ class ac_decomposition_impl generate_support_minimization_encodings(); /* always solves exactly for power of 2 */ - if ( __builtin_popcount( best_multiplicity ) == 1 ) + if ( __builtin_popcount( best_multiplicity ) == 1 && best_multiplicity <= 8 ) solve_min_support_exact( isets, best_free_set ); else solve_min_support_heuristic( isets, best_free_set ); @@ -876,9 +879,8 @@ class ac_decomposition_impl template bool create_covering_matrix( std::vector const& isets, std::vector& matrix, uint32_t free_set_size, bool sort ) { - assert( best_multiplicity < 12 ); + assert( best_multiplicity <= 16 ); uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; - uint64_t sol_existance = 0; uint32_t iset_support = num_vars - free_set_size; /* insert dichotomies */ @@ -897,7 +899,7 @@ class ac_decomposition_impl } /* compute function and distinguishable seed dichotomies */ - uint64_t column = 0; + uint64_t column[2] = { 0, 0 }; STT tt; STT care; uint32_t pair_pointer = 0; @@ -921,7 +923,7 @@ class ac_decomposition_impl /* if is are in diffent sets */ if ( ( ( ( onset_shift & ( offset >> k ) ) | ( ( onset >> k ) & offset_shift ) ) & 1 ) ) { - column |= UINT64_C( 1 ) << ( pair_pointer ); + column[pair_pointer >> 6u] |= UINT64_C( 1 ) << ( pair_pointer & 0x3F ); } ++pair_pointer; @@ -949,17 +951,15 @@ class ac_decomposition_impl float sort_cost = 0; if constexpr ( UseHeuristic ) { - sort_cost = 1.0f / ( __builtin_popcountl( column ) ); + sort_cost = 1.0f / ( __builtin_popcountl( column[0] ) + __builtin_popcountl( column[1] ) ); } else { - sort_cost = cost + ( ( combinations - __builtin_popcountl( column ) ) << num_vars ); + sort_cost = cost + ( ( combinations - __builtin_popcountl( column[0] + __builtin_popcountl( column[1] ) ) ) << num_vars ); } /* insert */ - matrix.emplace_back( encoding_matrix{ column, cost, i, sort_cost } ); - - sol_existance |= column; + matrix.emplace_back( encoding_matrix{ { column[0], column[1] }, cost, i, sort_cost } ); } if ( !sort ) @@ -1013,7 +1013,7 @@ class ac_decomposition_impl continue; /* check validity */ - if ( __builtin_popcountl( matrix[i].column | matrix[j].column ) == combinations ) + if ( __builtin_popcountl( matrix[i].column[0] | matrix[j].column[0] ) + __builtin_popcountl( matrix[i].column[1] | matrix[j].column[1] ) == combinations ) { res[0] = i; res[1] = j; @@ -1045,7 +1045,8 @@ class ac_decomposition_impl for ( uint32_t j = 1; j < matrix.size() - 1 && looping; ++j ) { - uint64_t current_columns = matrix[i].column | matrix[j].column; + uint64_t current_columns0 = matrix[i].column[0] | matrix[j].column[0]; + uint64_t current_columns1 = matrix[i].column[1] | matrix[j].column[1]; uint32_t current_cost = matrix[i].cost + matrix[j].cost; /* limit */ @@ -1093,7 +1094,7 @@ class ac_decomposition_impl continue; /* check validity */ - if ( __builtin_popcountl( current_columns | matrix[k].column ) == combinations ) + if ( __builtin_popcountl( current_columns0 | matrix[k].column[0] ) + __builtin_popcountl( current_columns1 | matrix[k].column[1] ) == combinations ) { res[0] = i; res[1] = j; @@ -1127,7 +1128,8 @@ class ac_decomposition_impl for ( uint32_t j = 1; j < matrix.size() - 2 && looping; ++j ) { - uint64_t current_columns0 = matrix[i].column | matrix[j].column; + uint64_t current_columns0 = matrix[i].column[0] | matrix[j].column[0]; + uint64_t current_columns1 = matrix[i].column[1] | matrix[j].column[1]; uint32_t current_cost0 = matrix[i].cost + matrix[j].cost; /* limit */ @@ -1154,7 +1156,8 @@ class ac_decomposition_impl for ( uint32_t k = 2; k < matrix.size() - 1 && looping; ++k ) { - uint64_t current_columns1 = current_columns0 | matrix[k].column; + uint64_t current_columns00 = current_columns0 | matrix[k].column[0]; + uint64_t current_columns11 = current_columns1 | matrix[k].column[1]; uint32_t current_cost1 = current_cost0 + matrix[k].cost; /* limit */ @@ -1202,7 +1205,7 @@ class ac_decomposition_impl continue; /* check validity */ - if ( __builtin_popcountl( current_columns1 | matrix[t].column ) == combinations ) + if ( __builtin_popcountl( current_columns00 | matrix[t].column[0] ) + __builtin_popcountl( current_columns11 | matrix[t].column[1] ) == combinations ) { res[0] = i; res[1] = j; @@ -1224,7 +1227,7 @@ class ac_decomposition_impl /* last value of res contains the size of the bound set */ std::array res = { UINT32_MAX }; uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; - uint64_t column = 0; + uint64_t column0 = 0, column1 = 0; uint32_t best = 0; float best_cost = std::numeric_limits::max(); @@ -1238,20 +1241,21 @@ class ac_decomposition_impl } /* select */ - column = matrix[best].column; + column0 = matrix[best].column[0]; + column1 = matrix[best].column[1]; std::swap( matrix[0], matrix[best] ); /* get max number of BS's */ uint32_t iter = 1; - while ( iter < ps.lut_size - best_free_set && __builtin_popcountl( column ) != combinations ) + while ( iter < ps.lut_size - best_free_set && __builtin_popcountl( column0 ) + __builtin_popcountl( column1 ) != combinations ) { /* select column that minimizes the cost */ best = 0; best_cost = std::numeric_limits::max(); for ( uint32_t i = iter; i < matrix.size(); ++i ) { - float local_cost = 1.0f / __builtin_popcountl( matrix[i].column & ~column ); + float local_cost = 1.0f / ( __builtin_popcountl( matrix[i].column[0] & ~column0 ) + __builtin_popcountl( matrix[i].column[1] & ~column1 ) ); if ( local_cost < best_cost ) { best = i; @@ -1259,12 +1263,13 @@ class ac_decomposition_impl } } - column |= matrix[best].column; + column0 |= matrix[best].column[0]; + column1 |= matrix[best].column[1]; std::swap( matrix[iter], matrix[best] ); ++iter; } - if ( __builtin_popcountl( column ) == combinations ) + if ( __builtin_popcountl( column0 ) + __builtin_popcountl( column1 ) == combinations ) { for ( uint32_t i = 0; i < iter; ++i ) { @@ -1290,24 +1295,26 @@ class ac_decomposition_impl best_cost += matrix[solution[i]].cost; } - uint64_t column; + uint64_t column0, column1; for ( uint32_t i = 0; i < num_elements; ++i ) { /* remove element i */ local_cost = 0; - column = 0; + column0 = 0; + column1 = 0; for ( uint32_t j = 0; j < num_elements; ++j ) { if ( j == i ) continue; local_cost += matrix[solution[j]].cost; - column |= matrix[solution[j]].column; + column0 |= matrix[solution[j]].column[0]; + column1 |= matrix[solution[j]].column[1]; } /* search for a better replecemnts */ for ( uint32_t j = 0; j < matrix.size(); ++j ) { - if ( __builtin_popcount( column | matrix[j].column ) != combinations ) + if ( __builtin_popcount( column0 | matrix[j].column[0] ) + __builtin_popcount( column1 | matrix[j].column[1] ) != combinations ) continue; if ( local_cost + matrix[j].cost < best_cost ) { From acdd08fd9bc6792831fa67a2df9e8e1cfaf15d98 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Tue, 21 Nov 2023 11:47:56 +0100 Subject: [PATCH 48/67] Performance improvements --- src/acd/ac_decomposition.hpp | 39 ++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 0a05552e2d..3112e4c20c 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -59,7 +59,7 @@ struct ac_decomposition_params uint32_t lut_size{ 6 }; /*! \brief Perform decomposition if support reducing. */ - uint32_t max_free_set_vars{ 4 }; + uint32_t max_free_set_vars{ 5 }; /*! \brief Maximum number of iterations for covering. */ uint32_t max_iter{ 5000 }; @@ -67,6 +67,9 @@ struct ac_decomposition_params /*! \brief Perform decomposition if support reducing. */ bool support_reducing_only{ true }; + /*! \brief Commits the first feasible decomposition. */ + bool exit_of_feasible_decomposition{ true }; + /*! \brief If decomposition with delay profile fails, ignore it. */ bool try_no_late_arrival{ false }; }; @@ -98,7 +101,7 @@ class ac_decomposition_impl }; private: - static constexpr uint32_t max_num_vars = 10; + static constexpr uint32_t max_num_vars = 8; using STT = kitty::static_truth_table; public: @@ -149,8 +152,8 @@ class ac_decomposition_impl [this]( STT const& tt ) { return column_multiplicity<1u>( tt ); }, [this]( STT const& tt ) { return column_multiplicity<2u>( tt ); }, [this]( STT const& tt ) { return column_multiplicity<3u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity4<4u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } + [this]( STT const& tt ) { return column_multiplicity5<4u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } // slow, do not use }; for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i ) @@ -168,6 +171,11 @@ class ac_decomposition_impl best_multiplicity = cost; best_cost = cost + additional_cost; free_set_size = i; + + if ( ps.exit_of_feasible_decomposition ) + { + break; + } } } @@ -198,6 +206,11 @@ class ac_decomposition_impl best_multiplicity = cost; best_cost = cost + additional_cost; free_set_size = i; + + if ( ps.exit_of_feasible_decomposition ) + { + break; + } } } } @@ -339,9 +352,10 @@ class ac_decomposition_impl uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; uint64_t constexpr masks[] = { 0x0, 0x3, 0xF, 0xFF, 0xFFFF, 0xFFFFFFFF }; - std::unordered_set multiplicity_set; + static_assert( free_set_size == 5 || free_set_size == 4 ); - static_assert( free_set_size <= 5 ); + uint32_t size = 0; + std::array multiplicity_set; /* extract iset functions */ auto it = std::begin( tt ); @@ -349,13 +363,22 @@ class ac_decomposition_impl { for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) { - multiplicity_set.insert( *it & masks[free_set_size] ); + multiplicity_set[size++] = static_cast( *it & masks[free_set_size] ); *it >>= ( 1u << free_set_size ); } ++it; } - return static_cast( multiplicity_set.size() ); + std::sort( multiplicity_set.begin(), multiplicity_set.begin() + size ); + + /* count unique */ + uint32_t multiplicity = 1; + for ( auto i = 1u; i < size; ++i ) + { + multiplicity += multiplicity_set[i] != multiplicity_set[i - 1] ? 1 : 0; + } + + return multiplicity; } inline bool combinations_offset_next( uint32_t k, uint32_t offset, uint32_t *pComb, uint32_t *pInvPerm, STT& tt ) From 43f4dccb4f1c6a8ad7d591d5bf511ab7e94bec92 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Thu, 23 Nov 2023 16:29:33 +0100 Subject: [PATCH 49/67] run time improvements in computing the column multiplicity --- src/acd/ac_decomposition.hpp | 41 ++++++++++-------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 3112e4c20c..0b6101e534 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -101,7 +101,7 @@ class ac_decomposition_impl }; private: - static constexpr uint32_t max_num_vars = 8; + static constexpr uint32_t max_num_vars = 10; using STT = kitty::static_truth_table; public: @@ -153,7 +153,7 @@ class ac_decomposition_impl [this]( STT const& tt ) { return column_multiplicity<2u>( tt ); }, [this]( STT const& tt ) { return column_multiplicity<3u>( tt ); }, [this]( STT const& tt ) { return column_multiplicity5<4u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } // slow, do not use + [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } }; for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i ) @@ -290,7 +290,7 @@ class ac_decomposition_impl { uint64_t multiplicity_set[4] = { 0u, 0u, 0u, 0u }; uint32_t multiplicity = 0; - uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + uint32_t const num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; uint64_t constexpr masks_bits[] = { 0x0, 0x3, 0xF, 0x3F }; uint64_t constexpr masks_idx[] = { 0x0, 0x0, 0x0, 0x3 }; @@ -321,40 +321,16 @@ class ac_decomposition_impl return multiplicity; } - template - uint32_t column_multiplicity4( STT tt ) - { - unsigned char multiplicity_set[1 << 16] = { 0 }; - uint32_t multiplicity = 0; - uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; - uint64_t constexpr masks[] = { 0x0, 0x3, 0xF, 0xFF, 0xFFFF }; - - static_assert( free_set_size <= 4 ); - - /* extract iset functions */ - auto it = std::begin( tt ); - for ( auto i = 0u; i < num_blocks; ++i ) - { - for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) - { - multiplicity += multiplicity_set[*it & masks[free_set_size]]++ == 0 ? 1 : 0; - *it >>= ( 1u << free_set_size ); - } - ++it; - } - - return multiplicity; - } - template uint32_t column_multiplicity5( STT tt ) { - uint32_t num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; + uint32_t const num_blocks = ( num_vars > 6 ) ? ( 1u << ( num_vars - 6 ) ) : 1; uint64_t constexpr masks[] = { 0x0, 0x3, 0xF, 0xFF, 0xFFFF, 0xFFFFFFFF }; static_assert( free_set_size == 5 || free_set_size == 4 ); uint32_t size = 0; + uint64_t prev = -1; std::array multiplicity_set; /* extract iset functions */ @@ -363,7 +339,12 @@ class ac_decomposition_impl { for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) { - multiplicity_set[size++] = static_cast( *it & masks[free_set_size] ); + uint32_t fs_fn = static_cast( *it & masks[free_set_size] ); + if ( fs_fn != prev ) + { + multiplicity_set[size++] = fs_fn; + prev = fs_fn; + } *it >>= ( 1u << free_set_size ); } ++it; From 23cfcc1e1f5e7d4b5624a4c29d41e7479cc54ecc Mon Sep 17 00:00:00 2001 From: aletempiac Date: Fri, 24 Nov 2023 12:18:49 +0100 Subject: [PATCH 50/67] Improving efficiency and removing useless code --- src/acd/ac_decomposition.hpp | 481 +++++++++++------------------------ src/acd/ac_wrapper.cpp | 27 +- src/acd/ac_wrapper.h | 7 +- 3 files changed, 155 insertions(+), 360 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 0b6101e534..d63d6685d7 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -61,14 +61,11 @@ struct ac_decomposition_params /*! \brief Perform decomposition if support reducing. */ uint32_t max_free_set_vars{ 5 }; - /*! \brief Maximum number of iterations for covering. */ - uint32_t max_iter{ 5000 }; - /*! \brief Perform decomposition if support reducing. */ bool support_reducing_only{ true }; /*! \brief Commits the first feasible decomposition. */ - bool exit_of_feasible_decomposition{ true }; + bool exit_on_feasible_decomposition{ true }; /*! \brief If decomposition with delay profile fails, ignore it. */ bool try_no_late_arrival{ false }; @@ -88,16 +85,15 @@ struct ac_decomposition_result std::vector support; }; -template class ac_decomposition_impl { private: - struct encoding_matrix + struct encoding_column { uint64_t column[2]; - uint32_t cost{ 0 }; - uint32_t index{ 0 }; - float sort_cost{ 0 }; + uint32_t cost; + uint32_t index; + float sort_cost; }; private: @@ -105,15 +101,14 @@ class ac_decomposition_impl using STT = kitty::static_truth_table; public: - explicit ac_decomposition_impl( TT const& tt, uint32_t num_vars, ac_decomposition_params const& ps, ac_decomposition_stats* pst = nullptr ) - : num_vars( num_vars ), ps( ps ), pst( pst ), permutations( num_vars ) + explicit ac_decomposition_impl( uint32_t num_vars, ac_decomposition_params const& ps, ac_decomposition_stats* pst = nullptr ) + : num_vars( num_vars ), ps( ps ), pst( pst ) { - tt_start = tt; std::iota( permutations.begin(), permutations.end(), 0 ); } /*! \brief Runs ACD using late arriving variables */ - int run( unsigned delay_profile ) + int run( word *tt, unsigned delay_profile ) { /* truth table is too large for the settings */ if ( num_vars > max_num_vars ) @@ -130,15 +125,78 @@ class ac_decomposition_impl } /* convert to static TT */ - best_tt = kitty::extend_to( tt_start ); - best_multiplicity = UINT32_MAX; - uint32_t best_cost = UINT32_MAX; + init_truth_table( tt ); /* permute late arriving variables to be the least significant */ reposition_late_arriving_variables( delay_profile, late_arriving ); /* run ACD trying different bound sets and free sets */ - uint32_t free_set_size = late_arriving; + if ( !find_decomposition( delay_profile, late_arriving ) ) + { + return -1; + } + + /* return number of levels */ + return delay_profile == 0 ? 2 : 1; + } + + int compute_decomposition() + { + if ( best_multiplicity == UINT32_MAX ) + return -1; + + /* compute isets */ + std::vector isets = compute_isets(); + + generate_support_minimization_encodings(); + + /* solves exactly only for small multiplicities */ + if ( best_multiplicity <= 4u ) + solve_min_support_exact( isets ); + else + solve_min_support_heuristic( isets ); + + /* unfeasible decomposition */ + assert( !best_bound_sets.empty() ); + + return 0; + } + + unsigned get_profile() + { + unsigned profile = 0; + + if ( best_free_set > num_vars ) + return -1; + + for ( uint32_t i = 0; i < best_free_set; ++i ) + { + profile |= 1 << permutations[i]; + } + + return profile; + } + + std::vector get_result() + { + return dec_result; + } + + void get_decomposition( unsigned char *decompArray ) + { + if ( best_free_set > num_vars ) + return; + + dec_result = generate_decomposition( best_free_set ); + return get_decomposition_abc( decompArray ); + } + +private: + bool find_decomposition( unsigned& delay_profile, uint32_t late_arriving ) + { + best_multiplicity = UINT32_MAX; + best_free_set = UINT32_MAX; + uint32_t best_cost = UINT32_MAX; uint32_t offset = static_cast( late_arriving ); uint32_t start = std::max( offset, 1u ); @@ -148,6 +206,7 @@ class ac_decomposition_impl start = std::max( start, num_vars - ps.lut_size ); } + /* array of functions to compute the column multiplicity */ std::function column_multiplicity_fn[5] = { [this]( STT const& tt ) { return column_multiplicity<1u>( tt ); }, [this]( STT const& tt ) { return column_multiplicity<2u>( tt ); }, @@ -156,23 +215,24 @@ class ac_decomposition_impl [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } }; + /* find a feasible AC decomposition */ for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i ) { - /* TODO: add shared set */ - auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, offset, column_multiplicity_fn[i - 1] ); + auto [tt_p, perm, multiplicity] = enumerate_iset_combinations_offset( i, offset, column_multiplicity_fn[i - 1] ); /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; + /* check for feasible solution that improves the cost */ - if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost <= 16 ) + if ( multiplicity <= ( 1 << ( ps.lut_size - i ) ) && multiplicity + additional_cost < best_cost && multiplicity <= 16 ) { best_tt = tt_p; permutations = perm; - best_multiplicity = cost; - best_cost = cost + additional_cost; - free_set_size = i; + best_multiplicity = multiplicity; + best_cost = multiplicity + additional_cost; + best_free_set = i; - if ( ps.exit_of_feasible_decomposition ) + if ( ps.exit_on_feasible_decomposition ) { break; } @@ -180,7 +240,7 @@ class ac_decomposition_impl } if ( best_multiplicity == UINT32_MAX && ( !ps.try_no_late_arrival || late_arriving == 0 ) ) - return -1; + return false; /* try without the delay profile */ if ( best_multiplicity == UINT32_MAX && ps.try_no_late_arrival ) @@ -193,21 +253,21 @@ class ac_decomposition_impl for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i ) { - /* TODO: add shared set */ - auto [tt_p, perm, cost] = enumerate_iset_combinations_offset( i, 0, column_multiplicity_fn[i - 1] ); + auto [tt_p, perm, multiplicity] = enumerate_iset_combinations_offset( i, 0, column_multiplicity_fn[i - 1] ); /* additional cost if not support reducing */ uint32_t additional_cost = ( num_vars - i > ps.lut_size ) ? 128 : 0; + /* check for feasible solution that improves the cost */ - if ( cost <= ( 1 << ( ps.lut_size - i ) ) && cost + additional_cost < best_cost && cost <= 16 ) + if ( multiplicity <= ( 1 << ( ps.lut_size - i ) ) && multiplicity + additional_cost < best_cost && multiplicity <= 16 ) { best_tt = tt_p; permutations = perm; - best_multiplicity = cost; - best_cost = cost + additional_cost; - free_set_size = i; + best_multiplicity = multiplicity; + best_cost = multiplicity + additional_cost; + best_free_set = i; - if ( ps.exit_of_feasible_decomposition ) + if ( ps.exit_on_feasible_decomposition ) { break; } @@ -216,75 +276,26 @@ class ac_decomposition_impl } if ( best_multiplicity == UINT32_MAX ) - return -1; + return false; + /* estimation on number of LUTs */ pst->num_luts = best_multiplicity <= 2 ? 2 : best_multiplicity <= 4 ? 3 : best_multiplicity <= 8 ? 4 : 5; - best_free_set = free_set_size; - - /* return number of levels */ - return delay_profile == 0 ? 2 : 1; - } - - int compute_decomposition() - { - if ( best_multiplicity == UINT32_MAX ) - return -1; - - /* compute isets */ - std::vector isets = compute_isets( best_free_set ); - - generate_support_minimization_encodings(); - - /* always solves exactly for power of 2 */ - if ( __builtin_popcount( best_multiplicity ) == 1 && best_multiplicity <= 8 ) - solve_min_support_exact( isets, best_free_set ); - else - solve_min_support_heuristic( isets, best_free_set ); - - /* unfeasible decomposition */ - if ( best_bound_sets.empty() ) - { - solve_min_support_exact( isets, best_free_set ); - - if ( best_bound_sets.empty() ) - { - return -1; - } - } - return 0; + return true; } - unsigned get_profile() + void init_truth_table( word *tt_start ) { - unsigned profile = 0; + uint32_t const num_blocks = ( num_vars <= 6 ) ? 1 : ( 1 << ( num_vars - 6 ) ); - if ( best_free_set > num_vars ) - return -1; - - for ( uint32_t i = 0; i < best_free_set; ++i ) + for ( uint32_t i = 0; i < num_blocks; ++i ) { - profile |= 1 << permutations[i]; + best_tt._bits[i] = tt_start[i]; } - return profile; - } - - std::vector get_result() - { - return dec_result; - } - - void get_decomposition( unsigned char *decompArray ) - { - if ( best_free_set > num_vars ) - return; - - dec_result = generate_decomposition( best_free_set ); - return get_decomposition_abc( decompArray ); + local_extend_to( best_tt, num_vars ); } -private: template uint32_t column_multiplicity( STT tt ) { @@ -392,7 +403,7 @@ class ac_decomposition_impl } template - std::tuple, uint32_t> enumerate_iset_combinations_offset( uint32_t free_set_size, uint32_t offset, Fn&& fn ) + std::tuple, uint32_t> enumerate_iset_combinations_offset( uint32_t free_set_size, uint32_t offset, Fn&& fn ) { STT tt = best_tt; @@ -434,7 +445,7 @@ class ac_decomposition_impl } } while( combinations_offset_next( free_set_size, offset, pComb, pInvPerm, tt ) ); - std::vector res_perm( num_vars ); + std::array res_perm; for ( uint32_t i = 0; i < num_vars; ++i ) { res_perm[i] = permutations[bestPerm[i]]; @@ -443,10 +454,10 @@ class ac_decomposition_impl return std::make_tuple( best_tt, res_perm, best_cost ); } - std::vector compute_isets( uint32_t free_set_size, bool verbose = false ) + std::vector compute_isets( bool verbose = false ) { /* construct isets involved in multiplicity */ - uint32_t isets_support = num_vars - free_set_size; + uint32_t isets_support = num_vars - best_free_set; std::vector isets( best_multiplicity ); /* construct isets */ @@ -459,24 +470,24 @@ class ac_decomposition_impl auto it = std::begin( tt ); for ( auto i = 0u; i < num_blocks; ++i ) { - for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) + for ( auto j = 0; j < ( 64 >> best_free_set ); ++j ) { - uint64_t val = *it & masks[free_set_size]; + uint64_t val = *it & masks[best_free_set]; if ( auto el = column_to_iset.find( val ); el != column_to_iset.end() ) { - isets[el->second]._bits[i / ( 1u << free_set_size )] |= UINT64_C( 1 ) << ( j + offset ); + isets[el->second]._bits[i / ( 1u << best_free_set )] |= UINT64_C( 1 ) << ( j + offset ); } else { - isets[column_to_iset.size()]._bits[i / ( 1u << free_set_size )] |= UINT64_C( 1 ) << ( j + offset ); + isets[column_to_iset.size()]._bits[i / ( 1u << best_free_set )] |= UINT64_C( 1 ) << ( j + offset ); column_to_iset[val] = column_to_iset.size(); } - *it >>= ( 1u << free_set_size ); + *it >>= ( 1u << best_free_set ); } - offset = ( offset + ( 64 >> free_set_size ) ) % 64; + offset = ( offset + ( 64 >> best_free_set ) ) % 64; ++it; } @@ -489,11 +500,10 @@ class ac_decomposition_impl /* save free_set functions */ std::vector free_set_tts( best_multiplicity ); - /* TODO: possible conflict */ for ( auto const& pair : column_to_iset ) { free_set_tts[pair.second]._bits[0] = pair.first; - local_extend_to( free_set_tts[pair.second], free_set_size ); + local_extend_to( free_set_tts[pair.second], best_free_set ); } /* print isets and free set*/ @@ -666,12 +676,12 @@ class ac_decomposition_impl void generate_support_minimization_encodings() { uint32_t count = 0; - uint32_t num_combs_exact[4] = { 1, 3, 35, 6435 }; /* enable don't cares only if not a power of 2 */ uint32_t num_combs = 2; if ( __builtin_popcount( best_multiplicity ) == 1 ) { + uint32_t num_combs_exact[4] = { 1, 3, 35, 6435 }; for ( uint32_t i = 0; i < 4; ++i ) { if ( ( best_multiplicity >> i ) == 2u ) @@ -684,6 +694,7 @@ class ac_decomposition_impl } else { + /* combinations are 2*3^(mu - 1) */ for ( uint32_t i = 1; i < best_multiplicity; ++i ) { num_combs = ( num_combs << 1 ) + num_combs; @@ -704,14 +715,14 @@ class ac_decomposition_impl } template - void generate_support_minimization_encodings_rec( uint64_t onset, uint64_t offset, uint32_t var, uint32_t& count ) + void generate_support_minimization_encodings_rec( uint32_t onset, uint32_t offset, uint32_t var, uint32_t& count ) { if ( var == best_multiplicity ) { if constexpr ( !enable_dcset ) { /* sets must be equally populated */ - if ( __builtin_popcountl( onset ) != __builtin_popcountl( offset ) ) + if ( __builtin_popcount( onset ) != __builtin_popcount( offset ) ) { return; } @@ -723,7 +734,7 @@ class ac_decomposition_impl return; } - /* move var in DCSET */ + /* var in DCSET */ if constexpr ( enable_dcset ) { generate_support_minimization_encodings_rec( onset, offset, var + 1, count ); @@ -746,20 +757,20 @@ class ac_decomposition_impl offset &= ~( 1 << var ); } - void solve_min_support_exact( std::vector const& isets, uint32_t free_set_size ) + void solve_min_support_exact( std::vector const& isets ) { - std::vector matrix; + std::vector matrix; matrix.reserve( support_minimization_encodings.size() ); best_bound_sets.clear(); /* create covering matrix */ - if ( !create_covering_matrix( isets, matrix, free_set_size, best_multiplicity > 4 ) ) + if ( !create_covering_matrix( isets, matrix, false ) ) { return; } /* solve the covering problem */ - std::array solution = covering_solve_exact( matrix, 100, ps.max_iter ); + std::array solution = covering_solve_exact( matrix ); /* check for failed decomposition */ if ( solution[0] == UINT32_MAX ) @@ -770,8 +781,8 @@ class ac_decomposition_impl /* compute best bound sets */ uint32_t num_luts = 1 + solution[4]; uint32_t num_levels = 2; - uint32_t num_edges = free_set_size + solution[4]; - uint32_t isets_support = num_vars - free_set_size; + uint32_t num_edges = best_free_set + solution[4]; + uint32_t isets_support = num_vars - best_free_set; best_care_sets.clear(); best_iset_onset.clear(); best_iset_offset.clear(); @@ -811,14 +822,14 @@ class ac_decomposition_impl } } - void solve_min_support_heuristic( std::vector const& isets, uint32_t free_set_size ) + void solve_min_support_heuristic( std::vector const& isets ) { - std::vector matrix; + std::vector matrix; matrix.reserve( support_minimization_encodings.size() ); best_bound_sets.clear(); /* create covering matrix */ - if ( !create_covering_matrix( isets, matrix, free_set_size, true ) ) + if ( !create_covering_matrix( isets, matrix, true ) ) { return; } @@ -839,8 +850,8 @@ class ac_decomposition_impl /* compute best bound sets */ uint32_t num_luts = 1 + solution[4]; uint32_t num_levels = 2; - uint32_t num_edges = free_set_size + solution[4]; - uint32_t isets_support = num_vars - free_set_size; + uint32_t num_edges = best_free_set + solution[4]; + uint32_t isets_support = num_vars - best_free_set; best_care_sets.clear(); best_iset_onset.clear(); best_iset_offset.clear(); @@ -880,12 +891,12 @@ class ac_decomposition_impl } } - template - bool create_covering_matrix( std::vector const& isets, std::vector& matrix, uint32_t free_set_size, bool sort ) + template + bool create_covering_matrix( std::vector const& isets, std::vector& matrix, bool sort ) { assert( best_multiplicity <= 16 ); uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; - uint32_t iset_support = num_vars - free_set_size; + uint32_t iset_support = num_vars - best_free_set; /* insert dichotomies */ for ( uint32_t i = 0; i < support_minimization_encodings.size(); ++i ) @@ -924,7 +935,7 @@ class ac_decomposition_impl /* compute included seed dichotomies */ for ( uint32_t k = j + 1; k < best_multiplicity; ++k ) { - /* if is are in diffent sets */ + /* if are in diffent sets */ if ( ( ( ( onset_shift & ( offset >> k ) ) | ( ( onset >> k ) & offset_shift ) ) & 1 ) ) { column[pair_pointer >> 6u] |= UINT64_C( 1 ) << ( pair_pointer & 0x3F ); @@ -947,11 +958,6 @@ class ac_decomposition_impl if ( cost > ps.lut_size ) continue; - if ( cost > 1 ) - { - cost |= 1 << iset_support; - } - float sort_cost = 0; if constexpr ( UseHeuristic ) { @@ -963,7 +969,7 @@ class ac_decomposition_impl } /* insert */ - matrix.emplace_back( encoding_matrix{ { column[0], column[1] }, cost, i, sort_cost } ); + matrix.emplace_back( encoding_column{ { column[0], column[1] }, cost, i, sort_cost } ); } if ( !sort ) @@ -976,7 +982,6 @@ class ac_decomposition_impl std::sort( matrix.begin(), matrix.end(), [&]( auto const& a, auto const& b ) { return a.cost < b.cost; } ); - return true; } else { @@ -988,16 +993,14 @@ class ac_decomposition_impl return true; } - template - std::array covering_solve_exact( std::vector& matrix, uint32_t max_iter = 100, int32_t limit = 2000 ) + std::array covering_solve_exact( std::vector& matrix ) { /* last value of res contains the size of the bound set */ std::array res = { UINT32_MAX }; uint32_t best_cost = UINT32_MAX; uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; - bool looping = true; - assert( best_multiplicity <= 16 ); + assert( best_multiplicity <= 4 ); /* determine the number of needed loops*/ if ( best_multiplicity <= 2 ) @@ -1026,207 +1029,11 @@ class ac_decomposition_impl } } } - else if ( best_multiplicity <= 8 ) - { - res[4] = 3; - for ( uint32_t i = 0; i < matrix.size() - 2 && looping; ++i ) - { - /* limit */ - if constexpr ( limit_iter ) - { - if ( limit <= 0 ) - { - looping = false; - } - } - if constexpr ( limit_sol ) - { - if ( best_cost < UINT32_MAX && max_iter == 0 ) - { - looping = false; - } - } - - for ( uint32_t j = 1; j < matrix.size() - 1 && looping; ++j ) - { - uint64_t current_columns0 = matrix[i].column[0] | matrix[j].column[0]; - uint64_t current_columns1 = matrix[i].column[1] | matrix[j].column[1]; - uint32_t current_cost = matrix[i].cost + matrix[j].cost; - - /* limit */ - if constexpr ( limit_iter ) - { - if ( limit <= 0 ) - { - looping = false; - } - } - if constexpr ( limit_sol ) - { - if ( best_cost < UINT32_MAX && max_iter == 0 ) - { - looping = false; - } - } - - /* bound */ - if ( current_cost >= best_cost ) - { - continue; - } - - for ( uint32_t k = 2; k < matrix.size() && looping; ++k ) - { - /* limit */ - if constexpr ( limit_iter ) - { - if ( limit-- <= 0 ) - { - looping = false; - } - } - if constexpr ( limit_sol ) - { - if ( best_cost < UINT32_MAX && max_iter-- == 0 ) - { - looping = false; - } - } - - /* filter by cost */ - if ( current_cost + matrix[k].cost >= best_cost ) - continue; - - /* check validity */ - if ( __builtin_popcountl( current_columns0 | matrix[k].column[0] ) + __builtin_popcountl( current_columns1 | matrix[k].column[1] ) == combinations ) - { - res[0] = i; - res[1] = j; - res[2] = k; - best_cost = current_cost + matrix[k].cost; - } - } - } - } - } - else - { - res[4] = 4; - for ( uint32_t i = 0; i < matrix.size() - 3 && looping; ++i ) - { - /* limit */ - if constexpr ( limit_iter ) - { - if ( limit <= 0 ) - { - looping = false; - } - } - if constexpr ( limit_sol ) - { - if ( best_cost < UINT32_MAX && max_iter == 0 ) - { - looping = false; - } - } - - for ( uint32_t j = 1; j < matrix.size() - 2 && looping; ++j ) - { - uint64_t current_columns0 = matrix[i].column[0] | matrix[j].column[0]; - uint64_t current_columns1 = matrix[i].column[1] | matrix[j].column[1]; - uint32_t current_cost0 = matrix[i].cost + matrix[j].cost; - - /* limit */ - if constexpr ( limit_iter ) - { - if ( limit <= 0 ) - { - looping = false; - } - } - if constexpr ( limit_sol ) - { - if ( best_cost < UINT32_MAX && max_iter == 0 ) - { - looping = false; - } - } - - /* bound */ - if ( current_cost0 >= best_cost ) - { - continue; - } - - for ( uint32_t k = 2; k < matrix.size() - 1 && looping; ++k ) - { - uint64_t current_columns00 = current_columns0 | matrix[k].column[0]; - uint64_t current_columns11 = current_columns1 | matrix[k].column[1]; - uint32_t current_cost1 = current_cost0 + matrix[k].cost; - - /* limit */ - if constexpr ( limit_iter ) - { - if ( limit <= 0 ) - { - looping = false; - } - } - if constexpr ( limit_sol ) - { - if ( best_cost < UINT32_MAX && max_iter == 0 ) - { - looping = false; - } - } - - /* bound */ - if ( current_cost1 >= best_cost ) - { - continue; - } - - for ( uint32_t t = 3; t < matrix.size() && looping; ++t ) - { - /* limit */ - if constexpr ( limit_iter ) - { - if ( limit-- <= 0 ) - { - looping = false; - } - } - if constexpr ( limit_sol ) - { - if ( best_cost-- < UINT32_MAX && max_iter == 0 ) - { - looping = false; - } - } - - /* filter by cost */ - if ( current_cost1 + matrix[t].cost >= best_cost ) - continue; - - /* check validity */ - if ( __builtin_popcountl( current_columns00 | matrix[t].column[0] ) + __builtin_popcountl( current_columns11 | matrix[t].column[1] ) == combinations ) - { - res[0] = i; - res[1] = j; - res[2] = k; - res[3] = t; - best_cost = current_cost1 + matrix[t].cost; - } - } - } - } - } - } return res; } - std::array covering_solve_heuristic( std::vector& matrix ) + std::array covering_solve_heuristic( std::vector& matrix ) { /* last value of res contains the size of the bound set */ std::array res = { UINT32_MAX }; @@ -1285,7 +1092,7 @@ class ac_decomposition_impl return res; } - bool covering_improve( std::vector& matrix, std::array& solution ) + bool covering_improve( std::vector& matrix, std::array& solution ) { /* performs one iteration of local search */ uint32_t best_cost = 0, local_cost = 0; @@ -1431,6 +1238,19 @@ class ac_decomposition_impl return false; } + /* Decomposition format for ABC + * + * The record is an array of unsigned chars where: + * - the first unsigned char entry stores the number of unsigned chars in the record + * - the second entry stores the number of LUTs + * After this, several sub-records follow, each representing one LUT as follows: + * - an unsigned char entry listing the number of fanins + * - a list of fanins, from the LSB to the MSB of the truth table. The N inputs of the original function + * have indexes from 0 to N-1, followed by the internal signals in a topological order + * - the LUT truth table occupying 2^(M-3) bytes, where M is the fanin count of the LUT, from the LSB to the MSB. + * A 2-input LUT, which takes 4 bits, should be stretched to occupy 8 bits (one unsigned char) + * A 0- or 1-input LUT can be represented similarly but it is not expected that such LUTs will be represented + */ void get_decomposition_abc( unsigned char *decompArray ) { unsigned char *pArray = decompArray; @@ -1485,11 +1305,10 @@ class ac_decomposition_impl std::vector> support_minimization_encodings; - TT tt_start; uint32_t num_vars; ac_decomposition_params const& ps; ac_decomposition_stats* pst; - std::vector permutations; + std::array permutations; }; } // namespace mockturtle diff --git a/src/acd/ac_wrapper.cpp b/src/acd/ac_wrapper.cpp index 6bb41ca377..99e5747f2f 100644 --- a/src/acd/ac_wrapper.cpp +++ b/src/acd/ac_wrapper.cpp @@ -1,27 +1,17 @@ -// #include "base/main/main.h" #include "ac_wrapper.h" #include "ac_decomposition.hpp" -// ABC_NAMESPACE_IMPL_START - int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ) { using namespace mockturtle; - int num_blocks = ( nVars <= 6 ) ? 1 : ( 1 << ( nVars - 6 ) ); - - /* translate truth table into static table */ - kitty::dynamic_truth_table tt( nVars ); - for ( int i = 0; i < num_blocks; ++i ) - tt._bits[i] = pTruth[i]; - ac_decomposition_params ps; ps.lut_size = lutSize; ps.try_no_late_arrival = static_cast( try_no_late_arrival ); ac_decomposition_stats st; - ac_decomposition_impl acd( tt, nVars, ps, &st ); - int val = acd.run( *pdelay ); + ac_decomposition_impl acd( nVars, ps, &st ); + int val = acd.run( pTruth, *pdelay ); if ( val < 0 ) { @@ -39,19 +29,12 @@ int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, { using namespace mockturtle; - int num_blocks = ( nVars <= 6 ) ? 1 : ( 1 << ( nVars - 6 ) ); - - /* translate truth table into static table */ - kitty::dynamic_truth_table tt( nVars ); - for ( int i = 0; i < num_blocks; ++i ) - tt._bits[i] = pTruth[i]; - ac_decomposition_params ps; ps.lut_size = lutSize; ac_decomposition_stats st; - ac_decomposition_impl acd( tt, nVars, ps, &st ); - acd.run( *pdelay ); + ac_decomposition_impl acd( nVars, ps, &st ); + acd.run( pTruth, *pdelay ); int val = acd.compute_decomposition(); if ( val < 0 ) @@ -65,5 +48,3 @@ int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, acd.get_decomposition( decomposition ); return 0; } - -// ABC_NAMESPACE_IMPL_END \ No newline at end of file diff --git a/src/acd/ac_wrapper.h b/src/acd/ac_wrapper.h index 5e0af37877..c41b4aec73 100644 --- a/src/acd/ac_wrapper.h +++ b/src/acd/ac_wrapper.h @@ -1,13 +1,10 @@ -// #pragma once +#pragma once #ifndef __ACD_WRAPPER_H_ #define __ACD_WRAPPER_H_ -// #include "base/main/main.h" #include "misc/util/abc_global.h" #include "map/if/if.h" -// ABC_NAMESPACE_HEADER_START - #ifdef __cplusplus extern "C" { #endif @@ -19,6 +16,4 @@ int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, } #endif -// ABC_NAMESPACE_HEADER_END - #endif \ No newline at end of file From 6097fd43495b62bec793fa8ca4fbc429bc9130ae Mon Sep 17 00:00:00 2001 From: aletempiac Date: Fri, 24 Nov 2023 14:24:20 +0100 Subject: [PATCH 51/67] Code formatting --- src/acd/ac_decomposition.hpp | 170 +++++++++++++++++------------------ src/acd/ac_wrapper.cpp | 2 +- 2 files changed, 82 insertions(+), 90 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index d63d6685d7..829ea58552 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -44,10 +44,10 @@ #include "kitty_constants.hpp" #include "kitty_constructors.hpp" -#include "kitty_static_tt.hpp" #include "kitty_dynamic_tt.hpp" #include "kitty_operations.hpp" #include "kitty_operators.hpp" +#include "kitty_static_tt.hpp" namespace mockturtle { @@ -55,19 +55,19 @@ namespace mockturtle /*! \brief Parameters for ac_decomposition */ struct ac_decomposition_params { - /*! \brief LUT size for decomposition. */ + /*! \brief LUT size for decomposition (3 < num < 7). */ uint32_t lut_size{ 6 }; - /*! \brief Perform decomposition if support reducing. */ - uint32_t max_free_set_vars{ 5 }; + /*! \brief Maximum size of the free set (1 < num < 6). */ + uint32_t max_free_set_vars{ 4 }; - /*! \brief Perform decomposition if support reducing. */ + /*! \brief Perform only support reducing (2-level) decompositions. */ bool support_reducing_only{ true }; - /*! \brief Commits the first feasible decomposition. */ - bool exit_on_feasible_decomposition{ true }; + /*! \brief Use the first feasible decomposition found. */ + bool use_first{ true }; - /*! \brief If decomposition with delay profile fails, ignore it. */ + /*! \brief If decomposition with delay profile fails, try without. */ bool try_no_late_arrival{ false }; }; @@ -108,7 +108,7 @@ class ac_decomposition_impl } /*! \brief Runs ACD using late arriving variables */ - int run( word *tt, unsigned delay_profile ) + int run( word* ptt, unsigned delay_profile ) { /* truth table is too large for the settings */ if ( num_vars > max_num_vars ) @@ -125,7 +125,7 @@ class ac_decomposition_impl } /* convert to static TT */ - init_truth_table( tt ); + init_truth_table( ptt ); /* permute late arriving variables to be the least significant */ reposition_late_arriving_variables( delay_profile, late_arriving ); @@ -142,7 +142,7 @@ class ac_decomposition_impl int compute_decomposition() { - if ( best_multiplicity == UINT32_MAX ) + if ( best_multiplicity == UINT32_MAX ) return -1; /* compute isets */ @@ -168,7 +168,7 @@ class ac_decomposition_impl if ( best_free_set > num_vars ) return -1; - + for ( uint32_t i = 0; i < best_free_set; ++i ) { profile |= 1 << permutations[i]; @@ -177,17 +177,12 @@ class ac_decomposition_impl return profile; } - std::vector get_result() - { - return dec_result; - } - - void get_decomposition( unsigned char *decompArray ) + void get_decomposition( unsigned char* decompArray ) { if ( best_free_set > num_vars ) return; - dec_result = generate_decomposition( best_free_set ); + generate_decomposition(); return get_decomposition_abc( decompArray ); } @@ -208,12 +203,11 @@ class ac_decomposition_impl /* array of functions to compute the column multiplicity */ std::function column_multiplicity_fn[5] = { - [this]( STT const& tt ) { return column_multiplicity<1u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity<2u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity<3u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity5<4u>( tt ); }, - [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } - }; + [this]( STT const& tt ) { return column_multiplicity<1u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity<2u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity<3u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity5<4u>( tt ); }, + [this]( STT const& tt ) { return column_multiplicity5<5u>( tt ); } }; /* find a feasible AC decomposition */ for ( uint32_t i = start; i <= ps.lut_size - 1 && i <= ps.max_free_set_vars; ++i ) @@ -232,7 +226,7 @@ class ac_decomposition_impl best_cost = multiplicity + additional_cost; best_free_set = i; - if ( ps.exit_on_feasible_decomposition ) + if ( ps.use_first ) { break; } @@ -267,7 +261,7 @@ class ac_decomposition_impl best_cost = multiplicity + additional_cost; best_free_set = i; - if ( ps.exit_on_feasible_decomposition ) + if ( ps.use_first ) { break; } @@ -279,18 +273,20 @@ class ac_decomposition_impl return false; /* estimation on number of LUTs */ - pst->num_luts = best_multiplicity <= 2 ? 2 : best_multiplicity <= 4 ? 3 : best_multiplicity <= 8 ? 4 : 5; + pst->num_luts = best_multiplicity <= 2 ? 2 : best_multiplicity <= 4 ? 3 + : best_multiplicity <= 8 ? 4 + : 5; return true; } - void init_truth_table( word *tt_start ) + void init_truth_table( word* ptt ) { uint32_t const num_blocks = ( num_vars <= 6 ) ? 1 : ( 1 << ( num_vars - 6 ) ); for ( uint32_t i = 0; i < num_blocks; ++i ) { - best_tt._bits[i] = tt_start[i]; + best_tt._bits[i] = ptt[i]; } local_extend_to( best_tt, num_vars ); @@ -362,7 +358,7 @@ class ac_decomposition_impl } std::sort( multiplicity_set.begin(), multiplicity_set.begin() + size ); - + /* count unique */ uint32_t multiplicity = 1; for ( auto i = 1u; i < size; ++i ) @@ -373,7 +369,7 @@ class ac_decomposition_impl return multiplicity; } - inline bool combinations_offset_next( uint32_t k, uint32_t offset, uint32_t *pComb, uint32_t *pInvPerm, STT& tt ) + inline bool combinations_offset_next( uint32_t k, uint32_t offset, uint32_t* pComb, uint32_t* pInvPerm, STT& tt ) { uint32_t i; @@ -443,7 +439,7 @@ class ac_decomposition_impl bestPerm[i] = pComb[i]; } } - } while( combinations_offset_next( free_set_size, offset, pComb, pInvPerm, tt ) ); + } while ( combinations_offset_next( free_set_size, offset, pComb, pInvPerm, tt ) ); std::array res_perm; for ( uint32_t i = 0; i < num_vars; ++i ) @@ -525,10 +521,11 @@ class ac_decomposition_impl return isets; } - std::vector generate_decomposition( uint32_t free_set_size ) + void generate_decomposition() { - std::vector res; + dec_result.clear(); + uint32_t num_edges = 0; for ( uint32_t i = 0; i < best_bound_sets.size(); ++i ) { ac_decomposition_result dec; @@ -537,7 +534,7 @@ class ac_decomposition_impl /* compute and minimize support for bound set variables */ uint32_t k = 0; - for ( uint32_t j = 0; j < num_vars - free_set_size; ++j ) + for ( uint32_t j = 0; j < num_vars - best_free_set; ++j ) { if ( !kitty::has_var( tt, j ) ) continue; @@ -554,59 +551,64 @@ class ac_decomposition_impl kitty::swap_inplace( tt, k, j ); kitty::swap_inplace( care, k, j ); } - dec.support.push_back( permutations[free_set_size + j] ); + dec.support.push_back( permutations[best_free_set + j] ); ++k; } dec.tt = kitty::shrink_to( tt, dec.support.size() ); - res.push_back( dec ); + dec_result.push_back( dec ); + num_edges += dec.support.size() > 1 ? dec.support.size() : 0; } /* compute the decomposition for the top-level LUT */ - compute_top_lut_decomposition( res, free_set_size ); + compute_top_lut_decomposition(); - return res; + if ( pst ) + { + pst->num_luts = dec_result.size(); + pst->num_edges = num_edges + dec_result.back().support.size(); + } } - void compute_top_lut_decomposition( std::vector& res, uint32_t free_set_size ) + void compute_top_lut_decomposition() { - uint32_t top_vars = best_bound_sets.size() + free_set_size; + uint32_t top_vars = best_bound_sets.size() + best_free_set; assert( top_vars <= ps.lut_size ); /* extend bound set functions with free_set_size LSB vars */ kitty::dynamic_truth_table tt( top_vars ); /* compute support */ - res.emplace_back(); - for ( uint32_t i = 0; i < free_set_size; ++i ) + dec_result.emplace_back(); + for ( uint32_t i = 0; i < best_free_set; ++i ) { - res.back().support.push_back( permutations[i] ); + dec_result.back().support.push_back( permutations[i] ); } /* create functions for bound set */ std::vector bound_set_vars; - auto res_it = res.begin(); + auto res_it = dec_result.begin(); uint32_t offset = 0; for ( uint32_t i = 0; i < best_bound_sets.size(); ++i ) { bound_set_vars.emplace_back( top_vars ); - kitty::create_nth_var( bound_set_vars[i], free_set_size + i ); + kitty::create_nth_var( bound_set_vars[i], best_free_set + i ); - /* add bound-set variables to the support, remove buffers */ + /* add bound-set variables to the support, remove buffers (shared set) */ if ( res_it->support.size() == 1 ) { - res.back().support.push_back( res_it->support.front() ); + dec_result.back().support.push_back( res_it->support.front() ); /* it is a NOT */ if ( ( res_it->tt._bits[0] & 1 ) == 1 ) { bound_set_vars[i] = ~bound_set_vars[i]; } - res.erase( res_it ); + dec_result.erase( res_it ); ++offset; } else { - res.back().support.push_back( num_vars + i - offset ); + dec_result.back().support.push_back( num_vars + i - offset ); ++res_it; } } @@ -634,7 +636,7 @@ class ac_decomposition_impl } /* add top-level LUT to result */ - res.back().tt = tt; + dec_result.back().tt = tt; } inline void reposition_late_arriving_variables( unsigned delay_profile, uint32_t late_arriving ) @@ -704,14 +706,6 @@ class ac_decomposition_impl } assert( count == num_combs ); - - /* print combinations */ - // std::cout << "{ "; - // for ( auto const& entry : support_minimization_encodings ) - // { - // std::cout << "{ " << entry[0] << ", " << entry[1] << " }, "; - // } - // std::cout << "}\n"; } template @@ -770,7 +764,7 @@ class ac_decomposition_impl } /* solve the covering problem */ - std::array solution = covering_solve_exact( matrix ); + std::array solution = covering_solve_exact( matrix ); /* check for failed decomposition */ if ( solution[0] == UINT32_MAX ) @@ -779,14 +773,14 @@ class ac_decomposition_impl } /* compute best bound sets */ - uint32_t num_luts = 1 + solution[4]; + uint32_t num_luts = 1 + solution[5]; uint32_t num_levels = 2; - uint32_t num_edges = best_free_set + solution[4]; + uint32_t num_edges = best_free_set + solution[5]; uint32_t isets_support = num_vars - best_free_set; best_care_sets.clear(); best_iset_onset.clear(); best_iset_offset.clear(); - for ( uint32_t i = 0; i < solution[4]; ++i ) + for ( uint32_t i = 0; i < solution[5]; ++i ) { STT tt; STT care; @@ -835,7 +829,7 @@ class ac_decomposition_impl } /* solve the covering problem: heuristic pass + local search */ - std::array solution = covering_solve_heuristic( matrix ); + std::array solution = covering_solve_heuristic( matrix ); /* check for failed decomposition */ if ( solution[0] == UINT32_MAX ) @@ -848,14 +842,14 @@ class ac_decomposition_impl ; /* compute best bound sets */ - uint32_t num_luts = 1 + solution[4]; + uint32_t num_luts = 1 + solution[5]; uint32_t num_levels = 2; - uint32_t num_edges = best_free_set + solution[4]; + uint32_t num_edges = best_free_set + solution[5]; uint32_t isets_support = num_vars - best_free_set; best_care_sets.clear(); best_iset_onset.clear(); best_iset_offset.clear(); - for ( uint32_t i = 0; i < solution[4]; ++i ) + for ( uint32_t i = 0; i < solution[5]; ++i ) { STT tt; STT care; @@ -993,10 +987,10 @@ class ac_decomposition_impl return true; } - std::array covering_solve_exact( std::vector& matrix ) + std::array covering_solve_exact( std::vector& matrix ) { /* last value of res contains the size of the bound set */ - std::array res = { UINT32_MAX }; + std::array res = { UINT32_MAX }; uint32_t best_cost = UINT32_MAX; uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; @@ -1005,12 +999,12 @@ class ac_decomposition_impl /* determine the number of needed loops*/ if ( best_multiplicity <= 2 ) { - res[4] = 1; + res[5] = 1; res[0] = 0; } else if ( best_multiplicity <= 4 ) { - res[4] = 2; + res[5] = 2; for ( uint32_t i = 0; i < matrix.size() - 1; ++i ) { for ( uint32_t j = 1; j < matrix.size(); ++j ) @@ -1033,10 +1027,10 @@ class ac_decomposition_impl return res; } - std::array covering_solve_heuristic( std::vector& matrix ) + std::array covering_solve_heuristic( std::vector& matrix ) { /* last value of res contains the size of the bound set */ - std::array res = { UINT32_MAX }; + std::array res = { UINT32_MAX }; uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; uint64_t column0 = 0, column1 = 0; @@ -1086,17 +1080,17 @@ class ac_decomposition_impl { res[i] = i; } - res[4] = iter; + res[5] = iter; } return res; } - bool covering_improve( std::vector& matrix, std::array& solution ) + bool covering_improve( std::vector& matrix, std::array& solution ) { /* performs one iteration of local search */ uint32_t best_cost = 0, local_cost = 0; - uint32_t num_elements = solution[4]; + uint32_t num_elements = solution[5]; uint32_t combinations = ( best_multiplicity * ( best_multiplicity - 1 ) ) / 2; bool improved = false; @@ -1211,8 +1205,7 @@ class ac_decomposition_impl auto it_care = std::begin( care._bits ); while ( it_tt != std::begin( tt._bits ) + num_blocks ) { - if ( ( ( ( *it_tt >> ( uint64_t( 1 ) << var_index ) ) ^ *it_tt ) & kitty::detail::projections_neg[var_index] - & ( *it_care >> ( uint64_t( 1 ) << var_index ) ) & *it_care ) != 0 ) + if ( ( ( ( *it_tt >> ( uint64_t( 1 ) << var_index ) ) ^ *it_tt ) & kitty::detail::projections_neg[var_index] & ( *it_care >> ( uint64_t( 1 ) << var_index ) ) & *it_care ) != 0 ) { return true; } @@ -1251,28 +1244,27 @@ class ac_decomposition_impl * A 2-input LUT, which takes 4 bits, should be stretched to occupy 8 bits (one unsigned char) * A 0- or 1-input LUT can be represented similarly but it is not expected that such LUTs will be represented */ - void get_decomposition_abc( unsigned char *decompArray ) + void get_decomposition_abc( unsigned char* decompArray ) { - unsigned char *pArray = decompArray; + unsigned char* pArray = decompArray; unsigned char bytes = 2; /* write number of LUTs */ pArray++; - *pArray = dec_result.size(); - pArray++; + *pArray++ = dec_result.size(); /* write LUTs */ for ( ac_decomposition_result const& lut : dec_result ) { /* write fanin size*/ - *pArray = lut.support.size(); - pArray++; ++bytes; + *pArray++ = lut.support.size(); + ++bytes; /* write support */ for ( uint32_t i : lut.support ) { - *pArray = (unsigned char) i; - pArray++; ++bytes; + *pArray++ = (unsigned char)i; + ++bytes; } /* write truth table */ @@ -1282,8 +1274,8 @@ class ac_decomposition_impl { for ( uint32_t j = 0; j < tt_num_bytes; ++j ) { - *pArray = (unsigned char) ( ( lut.tt._bits[i] >> ( 8 * j ) ) & 0xFF ); - pArray++; ++bytes; + *pArray++ = (unsigned char)( ( lut.tt._bits[i] >> ( 8 * j ) ) & 0xFF ); + ++bytes; } } } diff --git a/src/acd/ac_wrapper.cpp b/src/acd/ac_wrapper.cpp index 99e5747f2f..27259b67af 100644 --- a/src/acd/ac_wrapper.cpp +++ b/src/acd/ac_wrapper.cpp @@ -7,7 +7,7 @@ int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, ac_decomposition_params ps; ps.lut_size = lutSize; - ps.try_no_late_arrival = static_cast( try_no_late_arrival ); + ps.try_no_late_arrival = static_cast( try_no_late_arrival ); /* TODO: additional tests */ ac_decomposition_stats st; ac_decomposition_impl acd( nVars, ps, &st ); From b3d2419d9a0175bfbfb7478a7131bd706a16126a Mon Sep 17 00:00:00 2001 From: aletempiac Date: Mon, 27 Nov 2023 13:38:36 +0100 Subject: [PATCH 52/67] Formatting, renaming, and cleaning code --- src/acd/ac_decomposition.hpp | 49 +++++++++++++++--------------------- src/acd/ac_wrapper.cpp | 22 ++++++++++++++-- src/acd/ac_wrapper.h | 18 +++++++++++++ src/base/abci/abc.c | 45 +++++++++++++++++++++++++++------ src/base/abci/abcIf.c | 16 ++++++------ src/map/if/if.h | 12 ++++----- src/map/if/ifCore.c | 28 +-------------------- src/map/if/ifCut.c | 2 +- src/map/if/ifDelay.c | 20 +++++++-------- src/map/if/ifMap.c | 14 +++++------ src/map/if/ifTime.c | 4 +-- 11 files changed, 131 insertions(+), 99 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 829ea58552..2b31614766 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -1,28 +1,20 @@ -/* mockturtle: C++ logic network library - * Copyright (C) 2018-2023 EPFL - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ +/**C++File************************************************************** + FileName [ac_decomposition.hpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Ashenhurst-Curtis decomposition.] + + Synopsis [Interface with the FPGA mapping package.] + + Author [Alessandro Tempia Calvino] + + Affiliation [EPFL] + + Date [Ver. 1.0. Started - November 20, 2023.] + +***********************************************************************/ /*! \file ac_decomposition.hpp \brief Ashenhurst-Curtis decomposition @@ -39,7 +31,6 @@ #include #include #include -#include #include #include "kitty_constants.hpp" @@ -49,7 +40,7 @@ #include "kitty_operators.hpp" #include "kitty_static_tt.hpp" -namespace mockturtle +namespace acd { /*! \brief Parameters for ac_decomposition */ @@ -346,10 +337,10 @@ class ac_decomposition_impl { for ( auto j = 0; j < ( 64 >> free_set_size ); ++j ) { - uint32_t fs_fn = static_cast( *it & masks[free_set_size] ); + uint64_t fs_fn = *it & masks[free_set_size]; if ( fs_fn != prev ) { - multiplicity_set[size++] = fs_fn; + multiplicity_set[size++] = static_cast( fs_fn ); prev = fs_fn; } *it >>= ( 1u << free_set_size ); @@ -1303,6 +1294,6 @@ class ac_decomposition_impl std::array permutations; }; -} // namespace mockturtle +} // namespace acd #endif // _ACD_H_ \ No newline at end of file diff --git a/src/acd/ac_wrapper.cpp b/src/acd/ac_wrapper.cpp index 27259b67af..baeee2fd6a 100644 --- a/src/acd/ac_wrapper.cpp +++ b/src/acd/ac_wrapper.cpp @@ -1,9 +1,27 @@ +/**C++File************************************************************** + + FileName [ac_wrapper.cpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Ashenhurst-Curtis decomposition.] + + Synopsis [Interface with the FPGA mapping package.] + + Author [Alessandro Tempia Calvino] + + Affiliation [EPFL] + + Date [Ver. 1.0. Started - November 20, 2023.] + +***********************************************************************/ + #include "ac_wrapper.h" #include "ac_decomposition.hpp" int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ) { - using namespace mockturtle; + using namespace acd; ac_decomposition_params ps; ps.lut_size = lutSize; @@ -27,7 +45,7 @@ int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ) { - using namespace mockturtle; + using namespace acd; ac_decomposition_params ps; ps.lut_size = lutSize; diff --git a/src/acd/ac_wrapper.h b/src/acd/ac_wrapper.h index c41b4aec73..ce39949fb2 100644 --- a/src/acd/ac_wrapper.h +++ b/src/acd/ac_wrapper.h @@ -1,3 +1,21 @@ +/**C++File************************************************************** + + FileName [ac_wrapper.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Ashenhurst-Curtis decomposition.] + + Synopsis [Interface with the FPGA mapping package.] + + Author [Alessandro Tempia Calvino] + + Affiliation [EPFL] + + Date [Ver. 1.0. Started - November 20, 2023.] + +***********************************************************************/ + #pragma once #ifndef __ACD_WRAPPER_H_ #define __ACD_WRAPPER_H_ diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 33b85e0bf0..89785887dd 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -19447,7 +19447,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) If_ManSetDefaultPars( pPars ); pPars->pLutLib = (If_LibLut_t *)Abc_FrameReadLibLut(); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYDEWSqaflepmrsdbgxyuojiktnczvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KCFAGRNTXYZDEWSqaflepmrsdbgxyzuojiktncvh" ) ) != EOF ) { switch ( c ) { @@ -19563,6 +19563,17 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( pPars->nAndDelay < 0 ) goto usage; break; + case 'Z': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-Z\" should be followed by a positive integer 3, 4, 5, or 6.\n" ); + goto usage; + } + pPars->nLutDecSize = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( pPars->nLutDecSize < 3 || pPars->nLutDecSize > 6 ) + goto usage; + break; case 'D': if ( globalUtilOptind >= argc ) { @@ -19652,6 +19663,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'y': pPars->fUserRecLib ^= 1; break; + case 'z': + pPars->fUserLutDec ^= 1; + break; case 'u': pPars->fUserSesLib ^= 1; break; @@ -19676,9 +19690,6 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'c': pPars->fUseTtPerm ^= 1; break; - case 'z': - pPars->fAcd ^= 1; - break; case 'v': pPars->fVerbose ^= 1; break; @@ -19794,6 +19805,25 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) pPars->fCutMin = 1; } + if ( pPars->fUserLutDec ) + { + if ( pPars->nLutDecSize == 0 ) + { + Abc_Print( -1, "LUT decomposition size (%d) must be set.\n", pPars->nLutDecSize ); + return 1; + } + if ( pPars->nLutDecSize >= pPars->nLutSize ) + { + Abc_Print( -1, "LUT size (%d) must be greater than the LUT decomposition size (%d).\n", pPars->nLutSize, pPars->nLutDecSize ); + return 1; + } + if ( pPars->nLutSize < 4 || pPars->nLutSize > 10 ) + { + Abc_Print( -1, "This feature only works for [4;10]-LUTs.\n" ); + return 1; + } + } + // enable truth table computation if cut minimization is selected if ( pPars->fCutMin ) { @@ -19810,7 +19840,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) pPars->pLutLib = NULL; } // modify for delay optimization - if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut || pPars->fAcd ) + if ( pPars->fDelayOpt || pPars->fDsdBalance || pPars->fDelayOptLut || pPars->fUserLutDec ) { pPars->fTruth = 1; pPars->fCutMin = 1; @@ -19956,7 +19986,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) sprintf(LutSize, "library" ); else sprintf(LutSize, "%d", pPars->nLutSize ); - Abc_Print( -2, "usage: if [-KCFAGRNTXY num] [-DEW float] [-S str] [-qarlepmsdbgxyuojiktncvh]\n" ); + Abc_Print( -2, "usage: if [-KCFAGRNTXYZ num] [-DEW float] [-S str] [-qarlepmsdbgxyzuojiktncvh]\n" ); Abc_Print( -2, "\t performs FPGA technology mapping of the network\n" ); Abc_Print( -2, "\t-K num : the number of LUT inputs (2 < num < %d) [default = %s]\n", IF_MAX_LUTSIZE+1, LutSize ); Abc_Print( -2, "\t-C num : the max number of priority cuts (0 < num < 2^12) [default = %d]\n", pPars->nCutsMax ); @@ -19968,6 +19998,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-T num : the type of LUT structures [default = any]\n" ); Abc_Print( -2, "\t-X num : delay of AND-gate in LUT library units [default = %d]\n", pPars->nAndDelay ); Abc_Print( -2, "\t-Y num : area of AND-gate in LUT library units [default = %d]\n", pPars->nAndArea ); + Abc_Print( -2, "\t-Z num : the number of LUT inputs for LUT decomposition [default = %d]\n", pPars->nLutDecSize ); Abc_Print( -2, "\t-D float : sets the delay constraint for the mapping [default = %s]\n", Buffer ); Abc_Print( -2, "\t-E float : sets epsilon used for tie-breaking [default = %f]\n", pPars->Epsilon ); Abc_Print( -2, "\t-W float : sets wire delay between adjects LUTs [default = %f]\n", pPars->WireDelay ); @@ -19985,6 +20016,7 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-g : toggles delay optimization by SOP balancing [default = %s]\n", pPars->fDelayOpt? "yes": "no" ); Abc_Print( -2, "\t-x : toggles delay optimization by DSD balancing [default = %s]\n", pPars->fDsdBalance? "yes": "no" ); Abc_Print( -2, "\t-y : toggles delay optimization with recorded library [default = %s]\n", pPars->fUserRecLib? "yes": "no" ); + Abc_Print( -2, "\t-z : toggles delay optimization with LUT decomposition [default = %s]\n", pPars->fUserLutDec? "yes": "no" ); Abc_Print( -2, "\t-u : toggles delay optimization with SAT-based library [default = %s]\n", pPars->fUserSesLib? "yes": "no" ); Abc_Print( -2, "\t-o : toggles using buffers to decouple combinational outputs [default = %s]\n", pPars->fUseBuffs? "yes": "no" ); Abc_Print( -2, "\t-j : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck07? "yes": "no" ); @@ -19993,7 +20025,6 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-t : toggles optimizing average rather than maximum level [default = %s]\n", pPars->fDoAverage? "yes": "no" ); Abc_Print( -2, "\t-n : toggles computing DSDs of the cut functions [default = %s]\n", pPars->fUseDsd? "yes": "no" ); Abc_Print( -2, "\t-c : toggles computing truth tables in a new way [default = %s]\n", pPars->fUseTtPerm? "yes": "no" ); - Abc_Print( -2, "\t-z : toggles using ACD decomposition [default = %s]\n", pPars->fAcd? "yes": "no" ); Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", pPars->fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : prints the command usage\n"); return 1; diff --git a/src/base/abci/abcIf.c b/src/base/abci/abcIf.c index b7d7962739..357d7d83ff 100644 --- a/src/base/abci/abcIf.c +++ b/src/base/abci/abcIf.c @@ -116,7 +116,7 @@ Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars ) pPars->pTimesReq = Abc_NtkGetCoRequiredFloats(pNtk); // update timing info to reflect logic level - if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib || pPars->fAcd) && pNtk->pManTime ) + if ( (pPars->fDelayOpt || pPars->fDsdBalance || pPars->fUserRecLib || pPars->fUserSesLib || pPars->fUserLutDec) && pNtk->pManTime ) { int c; if ( pNtk->AndGateDelay == 0.0 ) @@ -443,7 +443,7 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC int v; If_Obj_t * pIfLeaf; - if ( pCutBest->nLeaves <= 6 ) + if ( pCutBest->nLeaves <= pIfMan->pPars->nLutDecSize ) { /* add fanins */ If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, v ) @@ -456,11 +456,11 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC } // get the delay profile - unsigned delayProfile = pCutBest->acdDelay; + unsigned delayProfile = pCutBest->decDelay; // perform LUT-decomposition and return the LUT-structure unsigned char decompArray[92]; - int val = acd_decompose( pTruth, pCutBest->nLeaves, 6, &(delayProfile), decompArray ); + int val = acd_decompose( pTruth, pCutBest->nLeaves, pIfMan->pPars->nLutDecSize, &(delayProfile), decompArray ); assert( val == 0 ); // convert the LUT-structure into a set of logic nodes in Abc_Ntk_t @@ -474,7 +474,7 @@ Hop_Obj_t * Abc_NodeBuildFromMini( Hop_Man_t * pMan, If_Man_t * p, If_Cut_t * pC Abc_Obj_t *pNewNodes[5]; /* create intermediate LUTs*/ - assert( decompArray[1] - 1 <= 5 ); + assert( decompArray[1] <= 6 ); Abc_Obj_t * pFanin; for ( i = 0; i < decompArray[1]; ++i ) { @@ -577,14 +577,14 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t pNodeNew = Abc_NtkCreateNode( pNtkNew ); // if ( pIfMan->pPars->pLutLib && pIfMan->pPars->pLutLib->fVarPinDelays ) if ( !pIfMan->pPars->fDelayOpt && !pIfMan->pPars->fDelayOptLut && !pIfMan->pPars->fDsdBalance && !pIfMan->pPars->fUseTtPerm && - !pIfMan->pPars->pLutStruct && !pIfMan->pPars->fAcd && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->nGateSize ) + !pIfMan->pPars->pLutStruct && !pIfMan->pPars->fUserLutDec && !pIfMan->pPars->fUserRecLib && !pIfMan->pPars->fUserSesLib && !pIfMan->pPars->nGateSize ) If_CutRotatePins( pIfMan, pCutBest ); if ( pIfMan->pPars->fUseCnfs || pIfMan->pPars->fUseMv ) { If_CutForEachLeafReverse( pIfMan, pCutBest, pIfLeaf, i ) Abc_ObjAddFanin( pNodeNew, Abc_NodeFromIf_rec(pNtkNew, pIfMan, pIfLeaf, vCover) ); } - else if ( pIfMan->pPars->fAcd ) + else if ( pIfMan->pPars->fUserLutDec ) { If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, i ) Abc_NodeFromIf_rec(pNtkNew, pIfMan, pIfLeaf, vCover); @@ -642,7 +642,7 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t extern Hop_Obj_t * Abc_RecToHop3( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj ); pNodeNew->pData = Abc_RecToHop3( (Hop_Man_t *)pNtkNew->pManFunc, pIfMan, pCutBest, pIfObj ); } - else if ( pIfMan->pPars->fAcd ) + else if ( pIfMan->pPars->fUserLutDec ) { extern void Abc_DecRecordToHop( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj, Vec_Int_t * vMemory, Abc_Obj_t * pNodeTop ); Abc_DecRecordToHop( pNtkNew, pIfMan, pCutBest, pIfObj, vCover, pNodeNew ); diff --git a/src/map/if/if.h b/src/map/if/if.h index c3ba59be43..cc4d2926b7 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -113,6 +113,7 @@ struct If_Par_t_ int nStructType; // type of the structure int nAndDelay; // delay of AND-gate in LUT library units int nAndArea; // area of AND-gate in LUT library units + int nLutDecSize; // the LUT size for decomposition int fPreprocess; // preprossing int fArea; // area-oriented mapping int fFancy; // a fancy feature @@ -146,7 +147,7 @@ struct If_Par_t_ int fDeriveLuts; // enables deriving LUT structures int fDoAverage; // optimize average rather than maximum level int fHashMapping; // perform AIG hashing after mapping - int fAcd; // perform AIG hashing after mapping + int fUserLutDec; // perform AIG hashing after mapping int fVerbose; // the verbosity flag int fVerboseTrace; // the verbosity flag char * pLutStruct; // LUT structure @@ -281,7 +282,6 @@ struct If_Man_t_ int pDumpIns[16]; Vec_Str_t * vMarks; Vec_Int_t * vVisited2; - int useLimitAdc; // timing manager Tim_Man_t * pManTim; @@ -305,7 +305,6 @@ struct If_Cut_t_ int iCutFunc; // TT ID of the cut int uMaskFunc; // polarity bitmask unsigned uSign; // cut signature - unsigned acdDelay; // Computed pin delay during ACD unsigned Cost : 12; // the user's cost of the cut (related to IF_COST_MAX) unsigned fCompl : 1; // the complemented attribute unsigned fUser : 1; // using the user's area and delay @@ -313,6 +312,7 @@ struct If_Cut_t_ unsigned fAndCut : 1; // matched with AND gate unsigned nLimit : 8; // the maximum number of leaves unsigned nLeaves : 8; // the number of leaves + unsigned decDelay: 16; // pin-to-pin decomposition delay int pLeaves[0]; }; @@ -570,9 +570,9 @@ extern int If_CutSopBalancePinDelaysInt( Vec_Int_t * vCover, int * p extern int If_CutSopBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); extern int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ); extern int If_CutLutBalancePinDelays( If_Man_t * p, If_Cut_t * pCut, char * pPerm ); -extern int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, int fFirst ); -extern int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ); -extern float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required ); +extern int If_LutDecEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, int fFirst ); +extern int If_LutDecReEval( If_Man_t * p, If_Cut_t * pCut ); +extern float If_LutDecPinRequired( If_Man_t * p, If_Cut_t * pCut, int i, float required ); /*=== ifDsd.c =============================================================*/ extern If_DsdMan_t * If_DsdManAlloc( int nVars, int nLutSize ); extern void If_DsdManAllocIsops( If_DsdMan_t * p, int nLutSize ); diff --git a/src/map/if/ifCore.c b/src/map/if/ifCore.c index ad3c85179e..f7fcbca661 100644 --- a/src/map/if/ifCore.c +++ b/src/map/if/ifCore.c @@ -62,7 +62,7 @@ void If_ManSetDefaultPars( If_Par_t * pPars ) pPars->fPower = 0; pPars->fCutMin = 0; pPars->fBidec = 0; - pPars->fAcd = 0; + pPars->fUserLutDec = 0; pPars->fVerbose = 0; } @@ -107,16 +107,10 @@ int If_ManPerformMappingComb( If_Man_t * p ) If_Obj_t * pObj; abctime clkTotal = Abc_Clock(); int i; - p->useLimitAdc = 1; //p->vVisited2 = Vec_IntAlloc( 100 ); //p->vMarks = Vec_StrStart( If_ManObjNum(p) ); - // if ( p->pPars->fAcd ) - // { - // p->pPars->nLutSize = 6; - // } - // set arrival times and fanout estimates If_ManForEachCi( p, pObj, i ) { @@ -128,11 +122,7 @@ int If_ManPerformMappingComb( If_Man_t * p ) if ( p->pPars->fPreprocess && !p->pPars->fArea ) { // map for delay - if ( p->pPars->fAcd ) - p->useLimitAdc = 0; If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1, 1, "Delay" ); - if ( p->pPars->fAcd ) - p->useLimitAdc = 1; // map for delay second option p->pPars->fFancy = 1; @@ -155,33 +145,17 @@ int If_ManPerformMappingComb( If_Man_t * p ) // area flow oriented mapping for ( i = 0; i < p->pPars->nFlowIters; i++ ) { - // if ( p->pPars->fAcd && i == 0 ) - // { - // p->useLimitAdc = 0; - // } If_ManPerformMappingRound( p, p->pPars->nCutsMax, 1, 0, 0, "Flow" ); if ( p->pPars->fExpRed ) If_ManImproveMapping( p ); - // if ( p->pPars->fAcd && i == 0 ) - // { - // p->useLimitAdc = 1; - // } } // area oriented mapping for ( i = 0; i < p->pPars->nAreaIters; i++ ) { - // if ( p->pPars->fAcd && i == 0 ) - // { - // p->useLimitAdc = 0; - // } If_ManPerformMappingRound( p, p->pPars->nCutsMax, 2, 0, 0, "Area" ); if ( p->pPars->fExpRed ) If_ManImproveMapping( p ); - // if ( p->pPars->fAcd && i == 0 ) - // { - // p->useLimitAdc = 1; - // } } if ( p->pPars->fVerbose ) diff --git a/src/map/if/ifCut.c b/src/map/if/ifCut.c index 8d1cccba08..49850d3133 100644 --- a/src/map/if/ifCut.c +++ b/src/map/if/ifCut.c @@ -761,7 +761,7 @@ void If_CutSort( If_Man_t * p, If_Set_t * pCutSet, If_Cut_t * pCut ) if ( !pCut->fUseless && (p->pPars->fUseDsd || p->pPars->pFuncCell2 || p->pPars->fUseBat || - p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fAcd || + p->pPars->pLutStruct || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fEnableCheck07 || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->fUseDsdTune || p->pPars->fEnableCheck75 || p->pPars->fEnableCheck75u || p->pPars->fUseCheck1 || p->pPars->fUseCheck2) ) { diff --git a/src/map/if/ifDelay.c b/src/map/if/ifDelay.c index 90fab6b006..3514327c16 100644 --- a/src/map/if/ifDelay.c +++ b/src/map/if/ifDelay.c @@ -412,11 +412,11 @@ int If_CutLutBalanceEval( If_Man_t * p, If_Cut_t * pCut ) } } -int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, int fFirst ) +int If_LutDecEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, int fFirst ) { pCut->fUser = 1; pCut->Cost = pCut->nLeaves > 1 ? 1 : 0; - pCut->acdDelay = 0; + pCut->decDelay = 0; if ( pCut->nLeaves == 0 ) // const { assert( Abc_Lit2Var(If_CutTruthLit(pCut)) == 0 ); @@ -428,7 +428,7 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, in return (int)If_ObjCutBest(If_CutLeaf(p, pCut, 0))->Delay; } - int LutSize = 6; + int LutSize = p->pPars->nLutDecSize; int i, leaf_delay; int DelayMax = -1, nLeafMax = 0; unsigned uLeafMask = 0; @@ -450,7 +450,7 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, in } if ( If_CutLeaveNum(pCut) <= LutSize ) { - pCut->acdDelay = ( 1 << LutSize ) - 1; + pCut->decDelay = ( 1 << LutSize ) - 1; return DelayMax + 1; } @@ -473,7 +473,7 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, in } /* Too many late-arriving signals */ - if ( nLeafMax > LutSize / 2 ) + if ( nLeafMax == LutSize ) { if ( use_late_arrival ) { @@ -493,7 +493,7 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, in int val = acd_evaluate( pTruth, pCut->nLeaves, LutSize, &uLeafMask, &cost, !use_late_arrival ); /* not feasible decomposition */ - pCut->acdDelay = uLeafMask; + pCut->decDelay = uLeafMask; if ( val < 0 ) { pCut->Cost = IF_COST_MAX; @@ -505,7 +505,7 @@ int If_AcdEval( If_Man_t * p, If_Cut_t * pCut, If_Obj_t * pObj, int optDelay, in return DelayMax + val; } -int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ) +int If_LutDecReEval( If_Man_t * p, If_Cut_t * pCut ) { // pCut->fUser = 1; @@ -526,14 +526,14 @@ int If_AcdReEval( If_Man_t * p, If_Cut_t * pCut ) for ( i = 0; i < If_CutLeaveNum(pCut); i++ ) { leaf_delay = If_ObjCutBest(If_CutLeaf(p, pCut, i))->Delay; - leaf_delay += ( ( pCut->acdDelay >> i ) & 1 ) == 0 ? 2 : 1; + leaf_delay += ( ( pCut->decDelay >> i ) & 1 ) == 0 ? 2 : 1; DelayMax = Abc_MaxInt( leaf_delay, DelayMax ); } return DelayMax; } -float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required ) +float If_LutDecPinRequired( If_Man_t * p, If_Cut_t * pCut, int i, float required ) { if ( pCut->nLeaves == 0 ) // const { @@ -546,7 +546,7 @@ float If_AcdLeafProp( If_Man_t * p, If_Cut_t * pCut, int i, float required ) return 0; } - return ( ( pCut->acdDelay >> i ) & 1 ) == 0 ? 2 : 1; + return ( ( pCut->decDelay >> i ) & 1 ) == 0 ? 2 : 1; } /* diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index 69f2ead81a..bdd3ae4399 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -166,7 +166,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep If_Cut_t * pCut0R, * pCut1R; int fFunc0R, fFunc1R; int i, k, v, iCutDsd, fChange; - int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fAcd || + int fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUserLutDec || p->pPars->fUseDsdTune || p->pPars->fUseCofVars || p->pPars->fUseAndVars || p->pPars->fUse34Spec || p->pPars->pLutStruct || p->pPars->pFuncCell2 || p->pPars->fUseCheck1 || p->pPars->fUseCheck2; int fUseAndCut = (p->pPars->nAndDelay > 0) || (p->pPars->nAndArea > 0); assert( !If_ObjIsAnd(pObj->pFanin0) || pObj->pFanin0->pCutSet->nCuts > 0 ); @@ -208,9 +208,9 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->fUseless = 1; } } - else if ( p->pPars->fAcd ) + else if ( p->pPars->fUserLutDec ) { - pCut->Delay = If_AcdReEval( p, pCut ); + pCut->Delay = If_LutDecReEval( p, pCut ); } else if ( p->pPars->fDelayOptLut ) pCut->Delay = If_CutLutBalanceEval( p, pCut ); @@ -268,7 +268,7 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep if ( !If_CutMergeOrdered( p, pCut0, pCut1, pCut ) ) continue; } - if ( p->pPars->fAcd && p->useLimitAdc && pCut->nLeaves > 6 ) + if ( p->pPars->fUserLutDec && !fFirst && pCut->nLeaves > p->pPars->nLutDecSize ) continue; if ( pObj->fSpec && pCut->nLeaves == (unsigned)p->pPars->nLutSize ) continue; @@ -429,9 +429,9 @@ void If_ObjPerformMappingAnd( If_Man_t * p, If_Obj_t * pObj, int Mode, int fPrep pCut->Delay = If_CutDsdBalanceEval( p, pCut, NULL ); else if ( p->pPars->fUserRecLib ) pCut->Delay = If_CutDelayRecCost3( p, pCut, pObj ); - else if ( p->pPars->fAcd ) + else if ( p->pPars->fUserLutDec ) { - pCut->Delay = If_AcdEval( p, pCut, pObj, Mode == 0, fFirst ); + pCut->Delay = If_LutDecEval( p, pCut, pObj, Mode == 0, fFirst ); pCut->fUseless = pCut->Delay == ABC_INFINITY; } else if ( p->pPars->fUserSesLib ) @@ -518,7 +518,7 @@ void If_ObjPerformMappingChoice( If_Man_t * p, If_Obj_t * pObj, int Mode, int fP If_Set_t * pCutSet; If_Obj_t * pTemp; If_Cut_t * pCutTemp, * pCut; - int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUse34Spec || p->pPars->fAcd; + int i, fSave0 = p->pPars->fDelayOpt || p->pPars->fDelayOptLut || p->pPars->fDsdBalance || p->pPars->fUserRecLib || p->pPars->fUserSesLib || p->pPars->fUse34Spec || p->pPars->fUserLutDec; assert( pObj->pEquiv != NULL ); // prepare diff --git a/src/map/if/ifTime.c b/src/map/if/ifTime.c index 9bce5bc434..f208423846 100644 --- a/src/map/if/ifTime.c +++ b/src/map/if/ifTime.c @@ -211,11 +211,11 @@ void If_CutPropagateRequired( If_Man_t * p, If_Obj_t * pObj, If_Cut_t * pCut, fl pLeaf->Required = IF_MIN( pLeaf->Required, Required - pLutDelays[0] ); } } - else if ( p->pPars->fAcd ) + else if ( p->pPars->fUserLutDec ) { Required = ObjRequired; If_CutForEachLeaf( p, pCut, pLeaf, i ) - pLeaf->Required = IF_MIN( pLeaf->Required, Required - If_AcdLeafProp( p, pCut, i, ObjRequired ) ); + pLeaf->Required = IF_MIN( pLeaf->Required, Required - If_LutDecPinRequired( p, pCut, i, ObjRequired ) ); } else { From 16a3c5fc30dddd3dfeb8c815fda22b608a0bf8ce Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 9 Dec 2023 21:53:48 +0800 Subject: [PATCH 53/67] Add copying names in &saveaig and &loadaig. --- src/aig/gia/giaDup.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/aig/gia/giaDup.c b/src/aig/gia/giaDup.c index db4072d71b..dbedca099f 100644 --- a/src/aig/gia/giaDup.c +++ b/src/aig/gia/giaDup.c @@ -788,6 +788,11 @@ Gia_Man_t * Gia_ManDupWithAttributes( Gia_Man_t * p ) pNew->vConfigs = Vec_IntDup( p->vConfigs ); if ( p->pCellStr ) pNew->pCellStr = Abc_UtilStrsav( p->pCellStr ); + // copy names if present + if ( p->vNamesIn ) + pNew->vNamesIn = Vec_PtrDupStr( p->vNamesIn ); + if ( p->vNamesOut ) + pNew->vNamesOut = Vec_PtrDupStr( p->vNamesOut ); return pNew; } Gia_Man_t * Gia_ManDupRemovePis( Gia_Man_t * p, int nRemPis ) From 7fe92148ccddd86431b438d25afc0740e71de525 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 18 Dec 2023 21:04:31 +0900 Subject: [PATCH 54/67] New command to put computation to sleep. --- src/base/cmd/cmd.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index 708fc3f5b6..5a752a5d49 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -37,6 +37,7 @@ ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// static int CmdCommandTime ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int CmdCommandSleep ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandEcho ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandQuit ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int CmdCommandAbcrc ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -90,6 +91,7 @@ void Cmd_Init( Abc_Frame_t * pAbc ) Cmd_HistoryRead( pAbc ); Cmd_CommandAdd( pAbc, "Basic", "time", CmdCommandTime, 0 ); + Cmd_CommandAdd( pAbc, "Basic", "sleep", CmdCommandSleep, 0 ); Cmd_CommandAdd( pAbc, "Basic", "echo", CmdCommandEcho, 0 ); Cmd_CommandAdd( pAbc, "Basic", "quit", CmdCommandQuit, 0 ); Cmd_CommandAdd( pAbc, "Basic", "abcrc", CmdCommandAbcrc, 0 ); @@ -228,6 +230,54 @@ int CmdCommandTime( Abc_Frame_t * pAbc, int argc, char **argv ) return 1; } +/**Function******************************************************************** + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int CmdCommandSleep( Abc_Frame_t * pAbc, int argc, char **argv ) +{ + abctime clkStop; + int c, nSecs = 1; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "Nh" ) ) != EOF ) + { + switch ( c ) + { + case 'N': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-N\" should be followed by an integer.\n" ); + goto usage; + } + nSecs = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nSecs < 0 ) + goto usage; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + clkStop = Abc_Clock() + nSecs * CLOCKS_PER_SEC; + while ( Abc_Clock() < clkStop ); + return 0; + + usage: + fprintf( pAbc->Err, "usage: sleep [-N ] [-h]\n" ); + fprintf( pAbc->Err, " puts ABC to sleep for the given time\n" ); + fprintf( pAbc->Err, "-N num time in seconds [default = %d]\n", nSecs ); + fprintf( pAbc->Err, "-h print the command usage\n" ); + return 1; +} /**Function******************************************************************** Synopsis [] From 706112ebd8d84c7bd2e5fa7b589eb88319cb2636 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 19 Dec 2023 16:13:52 -0800 Subject: [PATCH 55/67] Micro-optimizations to speed up the Liberty parser by ~1.67x. Signed-off-by: Rasmus Munk Larsen --- src/map/scl/sclLiberty.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/map/scl/sclLiberty.c b/src/map/scl/sclLiberty.c index 3d62b68e55..d853f557bf 100644 --- a/src/map/scl/sclLiberty.c +++ b/src/map/scl/sclLiberty.c @@ -281,26 +281,38 @@ static inline char * Scl_LibertyFindMatch( char * pPos, char * pEnd ) assert( *pPos == '(' || *pPos == '{' ); if ( *pPos == '(' ) { - for ( ; pPos < pEnd; pPos++ ) - { - if ( *pPos == '(' ) + ++Counter; + ++pPos; + for ( ; pPos < pEnd; pPos++ ) + { + // Invariant: Counter > 0. + if ( *pPos == '(' ) { Counter++; - if ( *pPos == ')' ) + continue; + } + else if ( *pPos == ')' ) { Counter--; - if ( Counter == 0 ) - break; + if ( Counter == 0 ) + break; + } } } else { + ++Counter; + ++pPos; for ( ; pPos < pEnd; pPos++ ) { - if ( *pPos == '{' ) + // Invariant: Counter > 0. + if ( *pPos == '{' ) { Counter++; - if ( *pPos == '}' ) + continue; + } + else if ( *pPos == '}' ) { Counter--; - if ( Counter == 0 ) - break; + if ( Counter == 0 ) + break; + } } } assert( *pPos == ')' || *pPos == '}' ); @@ -317,10 +329,14 @@ static inline Scl_Pair_t Scl_LibertyUpdateHead( Scl_Tree_t * p, Scl_Pair_t Head char * pChar; for ( pChar = pBeg; pChar < pEnd; pChar++ ) { - if ( *pChar == '\n' ) + if ( *pChar == '\n' ) { p->nLines++; - if ( Scl_LibertyCharIsSpace(*pChar) ) + // Note: Scl_LibertyCharIsSpace returns true for '\n', so we can + // continue here and save the call to Scl_LibertyCharIsSpace. + continue; + } else if ( Scl_LibertyCharIsSpace(*pChar) ) { continue; + } pLastNonSpace = pChar; if ( pFirstNonSpace == NULL ) pFirstNonSpace = pChar; From 5978ccdb52394f2e92df41a895335eced0c4fe7a Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 21 Dec 2023 12:16:33 +0900 Subject: [PATCH 56/67] Updating sleep command to wait for file. --- src/base/cmd/cmd.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/base/cmd/cmd.c b/src/base/cmd/cmd.c index 5a752a5d49..a18387acde 100644 --- a/src/base/cmd/cmd.c +++ b/src/base/cmd/cmd.c @@ -244,6 +244,7 @@ int CmdCommandTime( Abc_Frame_t * pAbc, int argc, char **argv ) int CmdCommandSleep( Abc_Frame_t * pAbc, int argc, char **argv ) { abctime clkStop; + char * pFileName = NULL; int c, nSecs = 1; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "Nh" ) ) != EOF ) @@ -267,15 +268,25 @@ int CmdCommandSleep( Abc_Frame_t * pAbc, int argc, char **argv ) goto usage; } } + + if ( argc == globalUtilOptind + 1 ) { + FILE * pFile = NULL; + pFileName = argv[globalUtilOptind]; + while ( (pFile = fopen(pFileName, "rb")) == NULL ); + if ( pFile != NULL ) + fclose( pFile ); + } + clkStop = Abc_Clock() + nSecs * CLOCKS_PER_SEC; while ( Abc_Clock() < clkStop ); return 0; usage: - fprintf( pAbc->Err, "usage: sleep [-N ] [-h]\n" ); - fprintf( pAbc->Err, " puts ABC to sleep for the given time\n" ); - fprintf( pAbc->Err, "-N num time in seconds [default = %d]\n", nSecs ); - fprintf( pAbc->Err, "-h print the command usage\n" ); + fprintf( pAbc->Err, "usage: sleep [-N ] [-h] \n" ); + fprintf( pAbc->Err, "\t puts ABC to sleep for some time\n" ); + fprintf( pAbc->Err, "\t-N num : time duration in seconds [default = %d]\n", nSecs ); + fprintf( pAbc->Err, "\t-h : toggle printing the command usage\n" ); + fprintf( pAbc->Err, "\t : (optional) waiting begins after the file is created\n" ); return 1; } /**Function******************************************************************** From 7dcc10a254e780ca7c8e6047f0cc03b7717a148a Mon Sep 17 00:00:00 2001 From: aletempiac Date: Wed, 10 Jan 2024 15:18:39 +0100 Subject: [PATCH 57/67] Minor fixes --- src/acd/ac_decomposition.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 2b31614766..64155b7135 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -174,7 +174,7 @@ class ac_decomposition_impl return; generate_decomposition(); - return get_decomposition_abc( decompArray ); + get_decomposition_abc( decompArray ); } private: @@ -264,9 +264,12 @@ class ac_decomposition_impl return false; /* estimation on number of LUTs */ - pst->num_luts = best_multiplicity <= 2 ? 2 : best_multiplicity <= 4 ? 3 - : best_multiplicity <= 8 ? 4 - : 5; + if ( pst ) + { + pst->num_luts = best_multiplicity <= 2 ? 2 : best_multiplicity <= 4 ? 3 + : best_multiplicity <= 8 ? 4 + : 5; + } return true; } @@ -799,7 +802,7 @@ class ac_decomposition_impl best_iset_offset.push_back( offset ); } - if ( pst != nullptr ) + if ( pst ) { pst->num_luts = num_luts; pst->num_levels = num_levels; @@ -868,7 +871,7 @@ class ac_decomposition_impl best_iset_offset.push_back( offset ); } - if ( pst != nullptr ) + if ( pst ) { pst->num_luts = num_luts; pst->num_levels = num_levels; From dc68fe27f904ccd14932256db4d2579095021c0d Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 11 Jan 2024 19:45:42 -0800 Subject: [PATCH 58/67] Saving module interface. --- src/base/wlc/wlc.h | 2 +- src/base/wlc/wlcBlast.c | 65 +++++++++++++++++++++++++++++++++++++++ src/base/wlc/wlcCom.c | 18 ++++++++--- src/base/wlc/wlcReadVer.c | 31 ++++++++++++++++--- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/base/wlc/wlc.h b/src/base/wlc/wlc.h index 0b3bed6c0e..ac47433387 100644 --- a/src/base/wlc/wlc.h +++ b/src/base/wlc/wlc.h @@ -448,7 +448,7 @@ extern void Wlc_NtkDeleteSim( Vec_Ptr_t * p ); extern int Wlc_StdinProcessSmt( Abc_Frame_t * pAbc, char * pCmd ); /*=== wlcReadVer.c ========================================================*/ extern char * Wlc_PrsConvertInitValues( Wlc_Ntk_t * p ); -extern Wlc_Ntk_t * Wlc_ReadVer( char * pFileName, char * pStr ); +extern Wlc_Ntk_t * Wlc_ReadVer( char * pFileName, char * pStr, int fInter ); /*=== wlcUif.c ========================================================*/ extern Vec_Int_t * Wlc_NtkCollectAddMult( Wlc_Ntk_t * p, Wlc_BstPar_t * pPar, int * pCountA, int * CountM ); extern int Wlc_NtkPairIsUifable( Wlc_Ntk_t * p, Wlc_Obj_t * pObj, Wlc_Obj_t * pObj2 ); diff --git a/src/base/wlc/wlcBlast.c b/src/base/wlc/wlcBlast.c index 4ec1a49029..47d08da620 100644 --- a/src/base/wlc/wlcBlast.c +++ b/src/base/wlc/wlcBlast.c @@ -2667,6 +2667,71 @@ Vec_Int_t * Wlc_ComputePerm( Wlc_Ntk_t * pNtk, int nPis ) return vPerm; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Wlc_TransferPioNames( Wlc_Ntk_t * p, Gia_Man_t * pNew ) +{ + int fSkipBitRange = 0; + Wlc_Obj_t * pObj; int i, k; + Vec_PtrFreeP( &pNew->vNamesIn ); + Vec_PtrFreeP( &pNew->vNamesOut ); + pNew->vNamesIn = Vec_PtrAlloc( Gia_ManPiNum(pNew) ); + pNew->vNamesOut = Vec_PtrAlloc( Gia_ManPoNum(pNew) ); + // create input names + Wlc_NtkForEachCi( p, pObj, i ) + if ( Wlc_ObjIsPi(pObj) ) + { + char * pName = Wlc_ObjName(p, Wlc_ObjId(p, pObj)); + int nRange = Wlc_ObjRange( pObj ); + if ( fSkipBitRange && nRange == 1 ) + Vec_PtrPush( pNew->vNamesIn, Abc_UtilStrsav(pName) ); + else + for ( k = 0; k < nRange; k++ ) + { + char Buffer[1000]; + sprintf( Buffer, "%s[%d]", pName, pObj->Beg < pObj->End ? pObj->Beg+k : pObj->Beg-k ); + Vec_PtrPush( pNew->vNamesIn, Abc_UtilStrsav(Buffer) ); + //printf( "Writing %s\n", Buffer ); + } + } + // add real primary outputs + Wlc_NtkForEachCo( p, pObj, i ) + if ( Wlc_ObjIsPo(pObj) ) + { + char * pName = Wlc_ObjName(p, Wlc_ObjId(p, pObj)); + int nRange = Wlc_ObjRange( pObj ); + if ( fSkipBitRange && nRange == 1 ) + Vec_PtrPush( pNew->vNamesOut, Abc_UtilStrsav(pName) ); + else + for ( k = 0; k < nRange; k++ ) + { + char Buffer[1000]; + sprintf( Buffer, "%s[%d]", pName, pObj->Beg < pObj->End ? pObj->Beg+k : pObj->Beg-k ); + Vec_PtrPush( pNew->vNamesOut, Abc_UtilStrsav(Buffer) ); + } + } + if ( Vec_PtrSize(pNew->vNamesIn) != Gia_ManPiNum(pNew) ) + printf( "The number of input bits (%d) does not match the number of primary inputs (%d) in the current AIG.\n", Vec_PtrSize(pNew->vNamesIn), Gia_ManPiNum(pNew) ); + if ( Vec_PtrSize(pNew->vNamesOut) != Gia_ManPoNum(pNew) ) + printf( "The number of output bits (%d) does not match the number of primary inputs (%d) in the current AIG.\n", Vec_PtrSize(pNew->vNamesOut), Gia_ManPoNum(pNew) ); + if ( Vec_PtrSize(pNew->vNamesIn) != Gia_ManPiNum(pNew) || Vec_PtrSize(pNew->vNamesOut) != Gia_ManPoNum(pNew) ) + { + Vec_PtrFreeP( &pNew->vNamesIn ); + Vec_PtrFreeP( &pNew->vNamesOut ); + } + else + printf( "Successfully transferred the primary input/output names from the word-level design to the current AIG.\n" ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/wlc/wlcCom.c b/src/base/wlc/wlcCom.c index 13192a1eb8..d15a7723b7 100644 --- a/src/base/wlc/wlcCom.c +++ b/src/base/wlc/wlcCom.c @@ -149,14 +149,16 @@ void Wlc_SetNtk( Abc_Frame_t * pAbc, Wlc_Ntk_t * pNtk ) ******************************************************************************/ int Abc_CommandReadWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) { + extern void Wlc_TransferPioNames( Wlc_Ntk_t * p, Gia_Man_t * pNew ); FILE * pFile; Wlc_Ntk_t * pNtk = NULL; char * pFileName = NULL; int fOldParser = 0; int fPrintTree = 0; + int fInter = 0; int c, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "opvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "opivh" ) ) != EOF ) { switch ( c ) { @@ -166,6 +168,9 @@ int Abc_CommandReadWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'p': fPrintTree ^= 1; break; + case 'i': + fInter ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -193,8 +198,12 @@ int Abc_CommandReadWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) fclose( pFile ); // perform reading - if ( !strcmp( Extra_FileNameExtension(pFileName), "v" ) ) - pNtk = Wlc_ReadVer( pFileName, NULL ); + if ( !strcmp( Extra_FileNameExtension(pFileName), "v" ) ) + { + pNtk = Wlc_ReadVer( pFileName, NULL, fInter ); + if ( fInter && pAbc->pGia ) + Wlc_TransferPioNames( pNtk, pAbc->pGia ); + } else if ( !strcmp( Extra_FileNameExtension(pFileName), "smt" ) || !strcmp( Extra_FileNameExtension(pFileName), "smt2" ) ) pNtk = Wlc_ReadSmt( pFileName, fOldParser, fPrintTree ); else if ( !strcmp( Extra_FileNameExtension(pFileName), "ndr" ) ) @@ -207,10 +216,11 @@ int Abc_CommandReadWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) Wlc_AbcUpdateNtk( pAbc, pNtk ); return 0; usage: - Abc_Print( -2, "usage: %%read [-opvh] \n" ); + Abc_Print( -2, "usage: %%read [-opivh] \n" ); Abc_Print( -2, "\t reads word-level design from Verilog file\n" ); Abc_Print( -2, "\t-o : toggle using old SMT-LIB parser [default = %s]\n", fOldParser? "yes": "no" ); Abc_Print( -2, "\t-p : toggle printing parse SMT-LIB tree [default = %s]\n", fPrintTree? "yes": "no" ); + Abc_Print( -2, "\t-i : toggle reading interface only [default = %s]\n", fInter? "yes": "no" ); Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); return 1; diff --git a/src/base/wlc/wlcReadVer.c b/src/base/wlc/wlcReadVer.c index aff3eae8aa..f31528ea6e 100644 --- a/src/base/wlc/wlcReadVer.c +++ b/src/base/wlc/wlcReadVer.c @@ -951,7 +951,7 @@ int Wlc_PrsReadDeclaration( Wlc_Prs_t * p, char * pStart ) } return 1; } -int Wlc_PrsDerive( Wlc_Prs_t * p ) +int Wlc_PrsDerive( Wlc_Prs_t * p, int fInter ) { Wlc_Obj_t * pObj; char * pStart, * pName; @@ -1031,6 +1031,8 @@ int Wlc_PrsDerive( Wlc_Prs_t * p ) while ( (pName = Wlc_PrsStrtok( NULL, "(,)" )) ) { pName = Wlc_PrsSkipSpaces( pName ); + if ( fInter && Wlc_PrsStrCmp( pName, "wire" ) ) + return 0; if ( Wlc_PrsStrCmp( pName, "input" ) || Wlc_PrsStrCmp( pName, "output" ) || Wlc_PrsStrCmp( pName, "wire" ) ) { if ( !Wlc_PrsReadDeclaration( p, pName ) ) @@ -1095,12 +1097,16 @@ int Wlc_PrsDerive( Wlc_Prs_t * p ) // these are read as part of the interface else if ( Wlc_PrsStrCmp( pStart, "input" ) || Wlc_PrsStrCmp( pStart, "output" ) || Wlc_PrsStrCmp( pStart, "wire" ) || Wlc_PrsStrCmp( pStart, "reg" ) ) { + if ( fInter && (Wlc_PrsStrCmp( pStart, "wire" ) || Wlc_PrsStrCmp( pStart, "reg" )) ) + return 0; if ( !Wlc_PrsReadDeclaration( p, pStart ) ) return 0; } else if ( Wlc_PrsStrCmp( pStart, "assign" ) ) { int Type, NameId, fFound, XValue = 0; + if ( fInter ) + return 0; pStart += strlen("assign"); // read name pStart = Wlc_PrsFindName( pStart, &pName ); @@ -1159,6 +1165,8 @@ int Wlc_PrsDerive( Wlc_Prs_t * p ) { // THIS IS A HACK to detect always statement representing combinational MUX int NameId, NameIdOut = -1, fFound, nValues, fDefaultFound = 0; + if ( fInter ) + return 0; // find control pStart = Wlc_PrsFindWord( pStart, "case", &fFound ); if ( pStart == NULL ) @@ -1682,7 +1690,7 @@ int Wlc_PrsDerive( Wlc_Prs_t * p ) } return 1; } -Wlc_Ntk_t * Wlc_ReadVer( char * pFileName, char * pStr ) +Wlc_Ntk_t * Wlc_ReadVer( char * pFileName, char * pStr, int fInter ) { Wlc_Prs_t * p; Wlc_Ntk_t * pNtk = NULL; @@ -1696,8 +1704,23 @@ Wlc_Ntk_t * Wlc_ReadVer( char * pFileName, char * pStr ) if ( !Wlc_PrsPrepare( p ) ) goto finish; // parse models - if ( !Wlc_PrsDerive( p ) ) + if ( !Wlc_PrsDerive( p, fInter ) ) + { + if ( fInter ) + { + printf( "Finished deriving interface for module \"%s\".\n", p->pNtk->pName ); + pNtk = p->pNtk; p->pNtk = NULL; + pNtk->pSpec = Abc_UtilStrsav( pFileName ); + if ( Vec_IntSize(&pNtk->vNameIds) == 0 ) + { + Vec_Int_t * vTemp = Vec_IntStartNatural( Wlc_NtkObjNumMax(pNtk) ); + pNtk->vNameIds = *vTemp, Vec_IntZero(vTemp); + Vec_IntFree( vTemp ); + } + return pNtk; + } goto finish; + } // derive topological order if ( p->pNtk ) { @@ -1728,7 +1751,7 @@ Wlc_Ntk_t * Wlc_ReadVer( char * pFileName, char * pStr ) void Io_ReadWordTest( char * pFileName ) { Gia_Man_t * pNew; - Wlc_Ntk_t * pNtk = Wlc_ReadVer( pFileName, NULL ); + Wlc_Ntk_t * pNtk = Wlc_ReadVer( pFileName, NULL, 0 ); if ( pNtk == NULL ) return; Wlc_WriteVer( pNtk, "test.v", 0, 0 ); From 8c7327b8df411654b7d38ccb678c500049fc2b5b Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 11 Jan 2024 22:19:50 -0800 Subject: [PATCH 59/67] Recognizing interface of the module when writing Verilog. --- src/aig/gia/giaMan.c | 133 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 123 insertions(+), 10 deletions(-) diff --git a/src/aig/gia/giaMan.c b/src/aig/gia/giaMan.c index e771f99cc4..e8fd9f1d87 100644 --- a/src/aig/gia/giaMan.c +++ b/src/aig/gia/giaMan.c @@ -1787,6 +1787,101 @@ void Gia_ManDumpVerilogNoInterAssign( Gia_Man_t * p, char * pFileName, Vec_Int_t Gia_ManSetRegNum( p, nRegs ); } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Gia_ManPrintOneName( FILE * pFile, char * pName, int Size ) +{ + int i; + for ( i = 0; i < Size; i++ ) + fprintf( pFile, "%c", pName[i] ); +} +int Gia_ManCountSymbs( char * pName ) +{ + int i; + for ( i = 0; pName[i]; i++ ) + if ( pName[i] == '[' ) + break; + return i; +} +int Gia_ManReadRangeNum( char * pName, int Size ) +{ + if ( pName[Size] == 0 ) + return -1; + assert( pName[Size] == '[' ); + return atoi(pName+Size+1); +} +Vec_Int_t * Gia_ManCountSymbsAll( Vec_Ptr_t * vNames ) +{ + char * pNameLast = (char *)Vec_PtrEntry(vNames, 0), * pName; + int i, nSymbsLast = Gia_ManCountSymbs(pNameLast); + Vec_Int_t * vArray = Vec_IntAlloc( Vec_PtrSize(vNames) * 2 ); + Vec_IntPush( vArray, 0 ); + Vec_IntPush( vArray, nSymbsLast ); + Vec_PtrForEachEntryStart( char *, vNames, pName, i, 1 ) + { + int nSymbs = Gia_ManCountSymbs(pName); + if ( nSymbs == nSymbsLast && !strncmp(pName, pNameLast, nSymbsLast) ) + continue; + Vec_IntPush( vArray, i ); + Vec_IntPush( vArray, nSymbs ); + pNameLast = pName; + nSymbsLast = nSymbs; + } + return vArray; +} +void Gia_ManDumpIoList( Gia_Man_t * p, FILE * pFile, int fOuts ) +{ + Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn; + if ( vNames == NULL ) + fprintf( pFile, "_%c_", fOuts ? 'o' : 'i' ); + else + { + Vec_Int_t * vArray = Gia_ManCountSymbsAll( vNames ); + int iName, Size, i; + Vec_IntForEachEntryDouble( vArray, iName, Size, i ) + { + if ( i ) fprintf( pFile, ", " ); + Gia_ManPrintOneName( pFile, (char *)Vec_PtrEntry(vNames, iName), Size ); + } + Vec_IntFree( vArray ); + } +} +void Gia_ManDumpIoRanges( Gia_Man_t * p, FILE * pFile, int fOuts ) +{ + Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn; + if ( p->vNamesOut == NULL ) + fprintf( pFile, "%s [%d:0] _%c_;\n", fOuts ? "output" : "input", fOuts ? Gia_ManPoNum(p)-1 : Gia_ManPiNum(p)-1, fOuts ? 'o' : 'i' ); + else + { + Vec_Int_t * vArray = Gia_ManCountSymbsAll( vNames ); + int iName, Size, i; + Vec_IntForEachEntryDouble( vArray, iName, Size, i ) + { + int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : Vec_PtrSize(vNames); + char * pName = (char *)Vec_PtrEntry(vNames, iName); + char * pNameLast = (char *)Vec_PtrEntry(vNames, iNameNext-1); + assert( !strncmp(pName, pNameLast, Size) ); + int NumBeg = Gia_ManReadRangeNum( pName, Size ); + int NumEnd = Gia_ManReadRangeNum( pNameLast, Size ); + fprintf( pFile, " %s ", fOuts ? "output" : "input" ); + if ( NumBeg != -1 && iName < iNameNext-1 ) + fprintf( pFile, "[%d:%d] ", NumEnd, NumBeg ); + Gia_ManPrintOneName( pFile, pName, Size ); + fprintf( pFile, ";\n" ); + } + Vec_IntFree( vArray ); + } +} + /**Function************************************************************* Synopsis [] @@ -1820,9 +1915,14 @@ void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ) fprintf( pFile, "module " ); Gia_ManDumpModuleName( pFile, p->pName ); fprintf( pFile, "_wrapper" ); - fprintf( pFile, " ( _i_, _o_ );\n\n" ); - fprintf( pFile, " input [%d:0] _i_;\n", Gia_ManCiNum(p)-1 ); - fprintf( pFile, " output [%d:0] _o_;\n\n", Gia_ManCoNum(p)-1 ); + fprintf( pFile, " ( " ); + Gia_ManDumpIoList( p, pFile, 0 ); + fprintf( pFile, ", " ); + Gia_ManDumpIoList( p, pFile, 1 ); + fprintf( pFile, " );\n\n" ); + Gia_ManDumpIoRanges( p, pFile, 0 ); + Gia_ManDumpIoRanges( p, pFile, 1 ); + fprintf( pFile, "\n" ); fprintf( pFile, " wire " ); Gia_ManWriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 8, 4, NULL ); @@ -1834,9 +1934,13 @@ void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ) fprintf( pFile, " assign { " ); Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, NULL ); - fprintf( pFile, " } = _i_;\n\n" ); + fprintf( pFile, " } = { " ); + Gia_ManDumpIoList( p, pFile, 0 ); + fprintf( pFile, " };\n\n" ); - fprintf( pFile, " assign _o_ = { " ); + fprintf( pFile, " assign { " ); + Gia_ManDumpIoList( p, pFile, 1 ); + fprintf( pFile, " } = { " ); Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, NULL ); fprintf( pFile, " };\n\n" ); @@ -1922,9 +2026,14 @@ void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName ) fprintf( pFile, "module " ); Gia_ManDumpModuleName( pFile, p->pName ); fprintf( pFile, "_wrapper" ); - fprintf( pFile, " ( _i_, _o_ );\n\n" ); - fprintf( pFile, " input [%d:0] _i_;\n", Gia_ManCiNum(p)-1 ); - fprintf( pFile, " output [%d:0] _o_;\n\n", Gia_ManCoNum(p)-1 ); + fprintf( pFile, " ( " ); + Gia_ManDumpIoList( p, pFile, 0 ); + fprintf( pFile, ", " ); + Gia_ManDumpIoList( p, pFile, 1 ); + fprintf( pFile, " );\n\n" ); + Gia_ManDumpIoRanges( p, pFile, 0 ); + Gia_ManDumpIoRanges( p, pFile, 1 ); + fprintf( pFile, "\n" ); fprintf( pFile, " wire " ); Gia_ManWriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 8, 4, NULL ); @@ -1936,9 +2045,13 @@ void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName ) fprintf( pFile, " assign { " ); Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, NULL ); - fprintf( pFile, " } = _i_;\n\n" ); + fprintf( pFile, " } = { " ); + Gia_ManDumpIoList( p, pFile, 0 ); + fprintf( pFile, " };\n\n" ); - fprintf( pFile, " assign _o_ = { " ); + fprintf( pFile, " assign { " ); + Gia_ManDumpIoList( p, pFile, 1 ); + fprintf( pFile, " } = { " ); Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, NULL ); fprintf( pFile, " };\n\n" ); From 38e632a954a61e02e3397e02d42142ef86fdd9cb Mon Sep 17 00:00:00 2001 From: aletempiac Date: Fri, 12 Jan 2024 14:50:34 +0100 Subject: [PATCH 60/67] Consider buffers in matrix covering as free --- src/acd/ac_decomposition.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/acd/ac_decomposition.hpp b/src/acd/ac_decomposition.hpp index 64155b7135..8ba2fb20e2 100644 --- a/src/acd/ac_decomposition.hpp +++ b/src/acd/ac_decomposition.hpp @@ -945,6 +945,10 @@ class ac_decomposition_impl /* discard solutions with support over LUT size */ if ( cost > ps.lut_size ) continue; + + /* buffers have zero cost */ + if ( cost == 1 ) + cost = 0; float sort_cost = 0; if constexpr ( UseHeuristic ) From 5bc99574fc63d4bc97b2e6342f1d3e16d5466cc5 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 12 Jan 2024 22:54:44 -0800 Subject: [PATCH 61/67] Eliminating dependency on "abc.rc" in "&deepsyn". --- src/aig/gia/giaDeep.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/aig/gia/giaDeep.c b/src/aig/gia/giaDeep.c index b58169f425..8d563726ff 100644 --- a/src/aig/gia/giaDeep.c +++ b/src/aig/gia/giaDeep.c @@ -55,6 +55,7 @@ Gia_Man_t * Gia_ManDeepSynOne( int nNoImpr, int TimeOut, int nAnds, int Seed, in Abc_Random(0); for ( i = 0; i < IterMax; i++ ) { + char * pCompress2rs = "balance -l; resub -K 6 -l; rewrite -l; resub -K 6 -N 2 -l; refactor -l; resub -K 8 -l; balance -l; resub -K 8 -N 2 -l; rewrite -l; resub -K 10 -l; rewrite -z -l; resub -K 10 -N 2 -l; balance -l; resub -K 12 -l; refactor -z -l; resub -K 12 -N 2 -l; rewrite -z -l; balance -l"; unsigned Rand = Abc_Random(0); int fDch = Rand & 1; //int fCom = (Rand >> 1) & 3; @@ -62,16 +63,16 @@ Gia_Man_t * Gia_ManDeepSynOne( int nNoImpr, int TimeOut, int nAnds, int Seed, in int fFx = (Rand >> 2) & 1; int KLut = fUseTwo ? 2 + (i % 5) : 3 + (i % 4); int fChange = 0; - char Command[1000]; - char * pComp = NULL; + char Command[2000]; + char pComp[1000]; if ( fCom == 3 ) - pComp = "; &put; compress2rs; compress2rs; compress2rs; &get"; + sprintf( pComp, "; &put; %s; %s; %s; &get", pCompress2rs, pCompress2rs, pCompress2rs ); else if ( fCom == 2 ) - pComp = "; &put; compress2rs; compress2rs; &get"; + sprintf( pComp, "; &put; %s; %s; &get", pCompress2rs, pCompress2rs ); else if ( fCom == 1 ) - pComp = "; &put; compress2rs; &get"; + sprintf( pComp, "; &put; %s; &get", pCompress2rs ); else if ( fCom == 0 ) - pComp = "; &dc2"; + sprintf( pComp, "; &dc2" ); sprintf( Command, "&dch%s; &if -a -K %d; &mfs -e -W 20 -L 20%s%s", fDch ? " -f" : "", KLut, fFx ? "; &fx; &st" : "", pComp ); if ( Abc_FrameIsBatchMode() ) From 67aab70cff96346e825ad351e26c69ff88948f50 Mon Sep 17 00:00:00 2001 From: aletempiac Date: Tue, 16 Jan 2024 17:42:43 +0100 Subject: [PATCH 62/67] Moving ACD package to if folder --- Makefile | 5 ++--- src/acd/module.make | 1 - src/{ => map/if}/acd/ac_decomposition.hpp | 0 src/{ => map/if}/acd/ac_wrapper.cpp | 0 src/{ => map/if}/acd/ac_wrapper.h | 0 src/{ => map/if}/acd/kitty_algorithm.hpp | 0 src/{ => map/if}/acd/kitty_constants.hpp | 0 src/{ => map/if}/acd/kitty_constructors.hpp | 0 src/{ => map/if}/acd/kitty_dynamic_tt.hpp | 0 src/{ => map/if}/acd/kitty_operations.hpp | 0 src/{ => map/if}/acd/kitty_operators.hpp | 0 src/{ => map/if}/acd/kitty_static_tt.hpp | 0 src/map/if/acd/module.make | 1 + src/map/if/if.h | 2 +- 14 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 src/acd/module.make rename src/{ => map/if}/acd/ac_decomposition.hpp (100%) rename src/{ => map/if}/acd/ac_wrapper.cpp (100%) rename src/{ => map/if}/acd/ac_wrapper.h (100%) rename src/{ => map/if}/acd/kitty_algorithm.hpp (100%) rename src/{ => map/if}/acd/kitty_constants.hpp (100%) rename src/{ => map/if}/acd/kitty_constructors.hpp (100%) rename src/{ => map/if}/acd/kitty_dynamic_tt.hpp (100%) rename src/{ => map/if}/acd/kitty_operations.hpp (100%) rename src/{ => map/if}/acd/kitty_operators.hpp (100%) rename src/{ => map/if}/acd/kitty_static_tt.hpp (100%) create mode 100644 src/map/if/acd/module.make diff --git a/Makefile b/Makefile index d770c3faf4..f7f4fda6fb 100644 --- a/Makefile +++ b/Makefile @@ -17,10 +17,9 @@ OS := $(shell uname -s) MODULES := \ $(wildcard src/ext*) \ - src/acd \ 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/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/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 \ @@ -55,7 +54,7 @@ endif ARCHFLAGS := $(ARCHFLAGS) -OPTFLAGS ?= -g -O +OPTFLAGS ?= -g -O3 CFLAGS += -std=c17 -Wall -Wno-unused-function -Wno-write-strings -Wno-sign-compare $(ARCHFLAGS) ifneq ($(findstring arm,$(shell uname -m)),) diff --git a/src/acd/module.make b/src/acd/module.make deleted file mode 100644 index b245d2c423..0000000000 --- a/src/acd/module.make +++ /dev/null @@ -1 +0,0 @@ -SRC += src/acd/ac_wrapper.cpp diff --git a/src/acd/ac_decomposition.hpp b/src/map/if/acd/ac_decomposition.hpp similarity index 100% rename from src/acd/ac_decomposition.hpp rename to src/map/if/acd/ac_decomposition.hpp diff --git a/src/acd/ac_wrapper.cpp b/src/map/if/acd/ac_wrapper.cpp similarity index 100% rename from src/acd/ac_wrapper.cpp rename to src/map/if/acd/ac_wrapper.cpp diff --git a/src/acd/ac_wrapper.h b/src/map/if/acd/ac_wrapper.h similarity index 100% rename from src/acd/ac_wrapper.h rename to src/map/if/acd/ac_wrapper.h diff --git a/src/acd/kitty_algorithm.hpp b/src/map/if/acd/kitty_algorithm.hpp similarity index 100% rename from src/acd/kitty_algorithm.hpp rename to src/map/if/acd/kitty_algorithm.hpp diff --git a/src/acd/kitty_constants.hpp b/src/map/if/acd/kitty_constants.hpp similarity index 100% rename from src/acd/kitty_constants.hpp rename to src/map/if/acd/kitty_constants.hpp diff --git a/src/acd/kitty_constructors.hpp b/src/map/if/acd/kitty_constructors.hpp similarity index 100% rename from src/acd/kitty_constructors.hpp rename to src/map/if/acd/kitty_constructors.hpp diff --git a/src/acd/kitty_dynamic_tt.hpp b/src/map/if/acd/kitty_dynamic_tt.hpp similarity index 100% rename from src/acd/kitty_dynamic_tt.hpp rename to src/map/if/acd/kitty_dynamic_tt.hpp diff --git a/src/acd/kitty_operations.hpp b/src/map/if/acd/kitty_operations.hpp similarity index 100% rename from src/acd/kitty_operations.hpp rename to src/map/if/acd/kitty_operations.hpp diff --git a/src/acd/kitty_operators.hpp b/src/map/if/acd/kitty_operators.hpp similarity index 100% rename from src/acd/kitty_operators.hpp rename to src/map/if/acd/kitty_operators.hpp diff --git a/src/acd/kitty_static_tt.hpp b/src/map/if/acd/kitty_static_tt.hpp similarity index 100% rename from src/acd/kitty_static_tt.hpp rename to src/map/if/acd/kitty_static_tt.hpp diff --git a/src/map/if/acd/module.make b/src/map/if/acd/module.make new file mode 100644 index 0000000000..33c59e8308 --- /dev/null +++ b/src/map/if/acd/module.make @@ -0,0 +1 @@ +SRC += src/map/if/acd/ac_wrapper.cpp diff --git a/src/map/if/if.h b/src/map/if/if.h index cc4d2926b7..f8c99fdf15 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -40,7 +40,7 @@ #include "opt/dau/dau.h" #include "misc/vec/vecHash.h" #include "misc/vec/vecWec.h" -#include "acd/ac_wrapper.h" +#include "map/if/acd/ac_wrapper.h" ABC_NAMESPACE_HEADER_START From 5a00bbaa8f930f9653fd24fabd948e78bb5784fb Mon Sep 17 00:00:00 2001 From: aletempiac Date: Tue, 16 Jan 2024 18:13:30 +0100 Subject: [PATCH 63/67] Cleaning Makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f7f4fda6fb..0cc979b750 100644 --- a/Makefile +++ b/Makefile @@ -54,9 +54,9 @@ endif ARCHFLAGS := $(ARCHFLAGS) -OPTFLAGS ?= -g -O3 +OPTFLAGS ?= -g -O -CFLAGS += -std=c17 -Wall -Wno-unused-function -Wno-write-strings -Wno-sign-compare $(ARCHFLAGS) +CFLAGS += -Wall -Wno-unused-function -Wno-write-strings -Wno-sign-compare $(ARCHFLAGS) ifneq ($(findstring arm,$(shell uname -m)),) CFLAGS += -DABC_MEMALIGN=4 endif From d140535d645cd948d2ebae6bc42677dac181f968 Mon Sep 17 00:00:00 2001 From: Baruch Sterin Date: Wed, 17 Jan 2024 15:04:31 -0800 Subject: [PATCH 64/67] Adapt previous merge by @aletempiac to compile with ABC namespaces. --- src/map/if/acd/ac_decomposition.hpp | 4 ++++ src/map/if/acd/ac_wrapper.cpp | 4 ++++ src/map/if/acd/ac_wrapper.h | 8 ++------ src/map/if/acd/kitty_algorithm.hpp | 4 ++++ src/map/if/acd/kitty_constants.hpp | 4 ++++ src/map/if/acd/kitty_constructors.hpp | 4 ++++ src/map/if/acd/kitty_dynamic_tt.hpp | 4 ++++ src/map/if/acd/kitty_operations.hpp | 4 ++++ src/map/if/acd/kitty_operators.hpp | 4 ++++ src/map/if/acd/kitty_static_tt.hpp | 4 ++++ 10 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/map/if/acd/ac_decomposition.hpp b/src/map/if/acd/ac_decomposition.hpp index 8ba2fb20e2..8aee0266d6 100644 --- a/src/map/if/acd/ac_decomposition.hpp +++ b/src/map/if/acd/ac_decomposition.hpp @@ -40,6 +40,8 @@ #include "kitty_operators.hpp" #include "kitty_static_tt.hpp" +ABC_NAMESPACE_CXX_HEADER_START + namespace acd { @@ -1303,4 +1305,6 @@ class ac_decomposition_impl } // namespace acd +ABC_NAMESPACE_CXX_HEADER_END + #endif // _ACD_H_ \ No newline at end of file diff --git a/src/map/if/acd/ac_wrapper.cpp b/src/map/if/acd/ac_wrapper.cpp index baeee2fd6a..fd8015f95e 100644 --- a/src/map/if/acd/ac_wrapper.cpp +++ b/src/map/if/acd/ac_wrapper.cpp @@ -19,6 +19,8 @@ #include "ac_wrapper.h" #include "ac_decomposition.hpp" +ABC_NAMESPACE_IMPL_START + int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ) { using namespace acd; @@ -66,3 +68,5 @@ int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, acd.get_decomposition( decomposition ); return 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/map/if/acd/ac_wrapper.h b/src/map/if/acd/ac_wrapper.h index ce39949fb2..a384b4404b 100644 --- a/src/map/if/acd/ac_wrapper.h +++ b/src/map/if/acd/ac_wrapper.h @@ -23,15 +23,11 @@ #include "misc/util/abc_global.h" #include "map/if/if.h" -#ifdef __cplusplus -extern "C" { -#endif +ABC_NAMESPACE_HEADER_START int acd_evaluate( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned *cost, int try_no_late_arrival ); int acd_decompose( word * pTruth, unsigned nVars, int lutSize, unsigned *pdelay, unsigned char *decomposition ); -#ifdef __cplusplus -} -#endif +ABC_NAMESPACE_HEADER_END #endif \ No newline at end of file diff --git a/src/map/if/acd/kitty_algorithm.hpp b/src/map/if/acd/kitty_algorithm.hpp index 6460a802cf..78eead08a2 100644 --- a/src/map/if/acd/kitty_algorithm.hpp +++ b/src/map/if/acd/kitty_algorithm.hpp @@ -9,6 +9,8 @@ #include "kitty_dynamic_tt.hpp" #include "kitty_static_tt.hpp" +ABC_NAMESPACE_CXX_HEADER_START + namespace kitty { @@ -116,4 +118,6 @@ void for_each_block_reversed( const TT& tt, Fn&& op ) } // namespace kitty +ABC_NAMESPACE_CXX_HEADER_END + #endif // _KITTY_ALGORITHM_H_ \ No newline at end of file diff --git a/src/map/if/acd/kitty_constants.hpp b/src/map/if/acd/kitty_constants.hpp index 55cfcd650f..35ff489e90 100644 --- a/src/map/if/acd/kitty_constants.hpp +++ b/src/map/if/acd/kitty_constants.hpp @@ -5,6 +5,8 @@ #include #include +ABC_NAMESPACE_CXX_HEADER_START + namespace kitty { @@ -88,4 +90,6 @@ static constexpr int32_t hex_to_int[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // namespace kitty +ABC_NAMESPACE_CXX_HEADER_END + #endif //_KITTY_CONSTANTS_H_ \ No newline at end of file diff --git a/src/map/if/acd/kitty_constructors.hpp b/src/map/if/acd/kitty_constructors.hpp index 43408b8cc3..26ec6e4835 100644 --- a/src/map/if/acd/kitty_constructors.hpp +++ b/src/map/if/acd/kitty_constructors.hpp @@ -12,6 +12,8 @@ #include "kitty_dynamic_tt.hpp" #include "kitty_static_tt.hpp" +ABC_NAMESPACE_CXX_HEADER_START + namespace kitty { @@ -89,4 +91,6 @@ void create_nth_var( TT& tt, uint8_t var_index, bool complement = false ) } // namespace kitty +ABC_NAMESPACE_CXX_HEADER_END + #endif // _KITTY_CONSTRUCT_TT_H_ \ No newline at end of file diff --git a/src/map/if/acd/kitty_dynamic_tt.hpp b/src/map/if/acd/kitty_dynamic_tt.hpp index f3ef0c7d9a..880943dfa6 100644 --- a/src/map/if/acd/kitty_dynamic_tt.hpp +++ b/src/map/if/acd/kitty_dynamic_tt.hpp @@ -8,6 +8,8 @@ #include "kitty_constants.hpp" +ABC_NAMESPACE_CXX_HEADER_START + namespace kitty { @@ -144,4 +146,6 @@ struct dynamic_truth_table } //namespace kitty +ABC_NAMESPACE_CXX_HEADER_END + #endif // _KITTY_DYNAMIC_TT_H_ \ No newline at end of file diff --git a/src/map/if/acd/kitty_operations.hpp b/src/map/if/acd/kitty_operations.hpp index fb504489a4..bf8e38007e 100644 --- a/src/map/if/acd/kitty_operations.hpp +++ b/src/map/if/acd/kitty_operations.hpp @@ -14,6 +14,8 @@ #include "kitty_dynamic_tt.hpp" #include "kitty_static_tt.hpp" +ABC_NAMESPACE_CXX_HEADER_START + namespace kitty { @@ -330,4 +332,6 @@ void print_hex( const TT& tt, std::ostream& os = std::cout ) } //namespace kitty +ABC_NAMESPACE_CXX_HEADER_END + #endif // _KITTY_OPERATIONS_TT_H_ \ No newline at end of file diff --git a/src/map/if/acd/kitty_operators.hpp b/src/map/if/acd/kitty_operators.hpp index 68a24cf2ec..b5f4688c2c 100644 --- a/src/map/if/acd/kitty_operators.hpp +++ b/src/map/if/acd/kitty_operators.hpp @@ -13,6 +13,8 @@ #include "kitty_static_tt.hpp" #include "kitty_operations.hpp" +ABC_NAMESPACE_CXX_HEADER_START + namespace kitty { @@ -119,4 +121,6 @@ inline void operator|=( static_truth_table& first, const static_truth_t } // namespace kitty +ABC_NAMESPACE_CXX_HEADER_END + #endif // _KITTY_OPERATORS_TT_H_ \ No newline at end of file diff --git a/src/map/if/acd/kitty_static_tt.hpp b/src/map/if/acd/kitty_static_tt.hpp index 61593f3ff1..ab5a5d1c93 100644 --- a/src/map/if/acd/kitty_static_tt.hpp +++ b/src/map/if/acd/kitty_static_tt.hpp @@ -7,6 +7,8 @@ #include "kitty_constants.hpp" +ABC_NAMESPACE_CXX_HEADER_START + namespace kitty { @@ -128,4 +130,6 @@ struct static_truth_table } //namespace kitty +ABC_NAMESPACE_CXX_HEADER_END + #endif // _KITTY_STATIC_TT_H_ \ No newline at end of file From 234af64a8cf0b027671320e0378d0da2be2da91a Mon Sep 17 00:00:00 2001 From: Baruch Sterin Date: Thu, 18 Jan 2024 09:58:18 -0800 Subject: [PATCH 65/67] Workaround for C++17 compilation (on clang) --- src/aig/gia/giaIso3.c | 2 +- src/base/acb/acbTest.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/aig/gia/giaIso3.c b/src/aig/gia/giaIso3.c index 8bea4bbfae..b526676d36 100644 --- a/src/aig/gia/giaIso3.c +++ b/src/aig/gia/giaIso3.c @@ -177,7 +177,7 @@ Vec_Wec_t * Gia_Iso4Gia( Gia_Man_t * p ) Vec_WecForEachLevel( vLevs, vLevel, l ) { Gia_Obj_t * pObj; int i; - int RandC[2] = { Abc_Random(0), Abc_Random(0) }; + unsigned RandC[2] = { Abc_Random(0), Abc_Random(0) }; if ( l == 0 ) { Gia_ManForEachObjVec( vLevel, p, pObj, i ) diff --git a/src/base/acb/acbTest.c b/src/base/acb/acbTest.c index 6290b88ea3..c22d4b55b3 100644 --- a/src/base/acb/acbTest.c +++ b/src/base/acb/acbTest.c @@ -421,8 +421,8 @@ Gia_Man_t * Acb_NtkGiaDeriveMiter( Gia_Man_t * pOne, Gia_Man_t * pTwo, int Type { for ( i = 0; i < Gia_ManCoNum(pOne); i += 2 ) { - int pLitsF[2] = { Gia_ManCo(pOne, i)->Value, Gia_ManCo(pOne, i+1)->Value }; - int pLitsS[2] = { Gia_ManCo(pTwo, i)->Value, Gia_ManCo(pTwo, i+1)->Value }; + unsigned pLitsF[2] = { Gia_ManCo(pOne, i)->Value, Gia_ManCo(pOne, i+1)->Value }; + unsigned pLitsS[2] = { Gia_ManCo(pTwo, i)->Value, Gia_ManCo(pTwo, i+1)->Value }; Gia_ManAppendCo( pNew, pLitsF[0] ); Gia_ManAppendCo( pNew, pLitsS[0] ); } @@ -431,8 +431,8 @@ Gia_Man_t * Acb_NtkGiaDeriveMiter( Gia_Man_t * pOne, Gia_Man_t * pTwo, int Type { for ( i = 0; i < Gia_ManCoNum(pOne); i += 2 ) { - int pLitsF[2] = { Gia_ManCo(pOne, i)->Value, Gia_ManCo(pOne, i+1)->Value }; - int pLitsS[2] = { Gia_ManCo(pTwo, i)->Value, Gia_ManCo(pTwo, i+1)->Value }; + unsigned pLitsF[2] = { Gia_ManCo(pOne, i)->Value, Gia_ManCo(pOne, i+1)->Value }; + unsigned pLitsS[2] = { Gia_ManCo(pTwo, i)->Value, Gia_ManCo(pTwo, i+1)->Value }; Gia_ManAppendCo( pNew, pLitsF[1] ); Gia_ManAppendCo( pNew, pLitsS[1] ); } @@ -441,8 +441,8 @@ Gia_Man_t * Acb_NtkGiaDeriveMiter( Gia_Man_t * pOne, Gia_Man_t * pTwo, int Type { for ( i = 0; i < Gia_ManCoNum(pOne); i += 2 ) { - int pLitsF[2] = { Gia_ManCo(pOne, i)->Value, Gia_ManCo(pOne, i+1)->Value }; - int pLitsS[2] = { Gia_ManCo(pTwo, i)->Value, Gia_ManCo(pTwo, i+1)->Value }; + int pLitsF[2] = { (int)Gia_ManCo(pOne, i)->Value, (int)Gia_ManCo(pOne, i+1)->Value }; + int pLitsS[2] = { (int)Gia_ManCo(pTwo, i)->Value, (int)Gia_ManCo(pTwo, i+1)->Value }; Gia_ManAppendCo( pNew, Gia_ManDualCompare( pNew, pLitsF, pLitsS ) ); } } From 8da884de85b09467eff6f0f813beeb28a4e77c2f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 18 Jan 2024 18:23:11 -0800 Subject: [PATCH 66/67] Switch to reverse the order of bits. --- src/aig/gia/gia.h | 2 +- src/aig/gia/giaMan.c | 28 ++++++++++++++-------------- src/base/abci/abc.c | 11 ++++++++--- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index 654f2faa5c..76c8fcb979 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -1530,7 +1530,7 @@ extern void Gia_ManPrintStatsMiter( Gia_Man_t * p, int fVerbose ) extern void Gia_ManSetRegNum( Gia_Man_t * p, int nRegs ); extern void Gia_ManReportImprovement( Gia_Man_t * p, Gia_Man_t * pNew ); extern void Gia_ManPrintNpnClasses( Gia_Man_t * p ); -extern void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb, int fAssign ); +extern void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb, int fAssign, int fReverse ); /*=== giaMem.c ===========================================================*/ extern Gia_MmFixed_t * Gia_MmFixedStart( int nEntrySize, int nEntriesMax ); extern void Gia_MmFixedStop( Gia_MmFixed_t * p, int fVerbose ); diff --git a/src/aig/gia/giaMan.c b/src/aig/gia/giaMan.c index e8fd9f1d87..7498630a81 100644 --- a/src/aig/gia/giaMan.c +++ b/src/aig/gia/giaMan.c @@ -1408,17 +1408,17 @@ void Gia_ManWriteNames( FILE * pFile, char c, int n, Vec_Ptr_t * vNames, int Sta fFirst = 0; } } -void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb, int fAssign ) +void Gia_ManDumpVerilog( Gia_Man_t * p, char * pFileName, Vec_Int_t * vObjs, int fVerBufs, int fInter, int fInterComb, int fAssign, int fReverse ) { if ( fInterComb ) { if ( fAssign ) { - extern void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName ); - Gia_ManDumpInterfaceAssign( p, pFileName ); + extern void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName, int fReverse ); + Gia_ManDumpInterfaceAssign( p, pFileName, fReverse ); } else { - extern void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ); - Gia_ManDumpInterface( p, pFileName ); + extern void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName, int fReverse ); + Gia_ManDumpInterface( p, pFileName, fReverse ); } } else @@ -1855,7 +1855,7 @@ void Gia_ManDumpIoList( Gia_Man_t * p, FILE * pFile, int fOuts ) Vec_IntFree( vArray ); } } -void Gia_ManDumpIoRanges( Gia_Man_t * p, FILE * pFile, int fOuts ) +void Gia_ManDumpIoRanges( Gia_Man_t * p, FILE * pFile, int fOuts, int fReverse ) { Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn; if ( p->vNamesOut == NULL ) @@ -1874,7 +1874,7 @@ void Gia_ManDumpIoRanges( Gia_Man_t * p, FILE * pFile, int fOuts ) int NumEnd = Gia_ManReadRangeNum( pNameLast, Size ); fprintf( pFile, " %s ", fOuts ? "output" : "input" ); if ( NumBeg != -1 && iName < iNameNext-1 ) - fprintf( pFile, "[%d:%d] ", NumEnd, NumBeg ); + fprintf( pFile, "[%d:%d] ", fReverse ? NumBeg : NumEnd, fReverse ? NumEnd : NumBeg ); Gia_ManPrintOneName( pFile, pName, Size ); fprintf( pFile, ";\n" ); } @@ -1893,7 +1893,7 @@ void Gia_ManDumpIoRanges( Gia_Man_t * p, FILE * pFile, int fOuts ) SeeAlso [] ***********************************************************************/ -void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ) +void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName, int fReverse ) { Gia_Obj_t * pObj; Vec_Bit_t * vInvs, * vUsed; @@ -1920,8 +1920,8 @@ void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ) fprintf( pFile, ", " ); Gia_ManDumpIoList( p, pFile, 1 ); fprintf( pFile, " );\n\n" ); - Gia_ManDumpIoRanges( p, pFile, 0 ); - Gia_ManDumpIoRanges( p, pFile, 1 ); + Gia_ManDumpIoRanges( p, pFile, 0, fReverse ); + Gia_ManDumpIoRanges( p, pFile, 1, fReverse ); fprintf( pFile, "\n" ); fprintf( pFile, " wire " ); @@ -2004,7 +2004,7 @@ void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName ) Vec_BitFree( vInvs ); Vec_BitFree( vUsed ); } -void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName ) +void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName, int fReverse ) { Gia_Obj_t * pObj; Vec_Bit_t * vInvs, * vUsed; @@ -2031,8 +2031,8 @@ void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName ) fprintf( pFile, ", " ); Gia_ManDumpIoList( p, pFile, 1 ); fprintf( pFile, " );\n\n" ); - Gia_ManDumpIoRanges( p, pFile, 0 ); - Gia_ManDumpIoRanges( p, pFile, 1 ); + Gia_ManDumpIoRanges( p, pFile, 0, fReverse ); + Gia_ManDumpIoRanges( p, pFile, 1, fReverse ); fprintf( pFile, "\n" ); fprintf( pFile, " wire " ); @@ -2189,7 +2189,7 @@ void Gia_GenSandwich( char ** pFNames, int nFNames, char * pFileName ) fprintf( pFile, "endmodule\n" ); fclose( pFile ); for ( i = 0; i < nFNames; i++ ) { - Gia_ManDumpVerilog( pGias[i], Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v"), NULL, 0, 0, 1, 0 ); + Gia_ManDumpVerilog( pGias[i], Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v"), NULL, 0, 0, 1, 0, 0 ); printf( "Dumped Verilog file \"%s\"\n", Extra_FileNameGenericAppend(pGias[i]->pSpec, ".v") ); } Gia_FreeMany( pGias, nFNames ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 89785887dd..bd0dd74cfc 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -32070,9 +32070,10 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) int fMiniAig = 0; int fMiniLut = 0; int fWriteNewLine = 0; + int fReverse = 0; int fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "upicabmlnvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "upicabmlnrvh" ) ) != EOF ) { switch ( c ) { @@ -32103,6 +32104,9 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'n': fWriteNewLine ^= 1; break; + case 'r': + fReverse ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -32132,7 +32136,7 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) Gia_ManStop( pGia ); } else if ( fVerilog ) - Gia_ManDumpVerilog( pAbc->pGia, pFileName, NULL, fVerBufs, fInter, fInterComb, fAssign ); + Gia_ManDumpVerilog( pAbc->pGia, pFileName, NULL, fVerBufs, fInter, fInterComb, fAssign, fReverse ); else if ( fMiniAig ) Gia_ManWriteMiniAig( pAbc->pGia, pFileName ); else if ( fMiniLut ) @@ -32142,7 +32146,7 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &w [-upicabmlnvh] \n" ); + Abc_Print( -2, "usage: &w [-upicabmlnrvh] \n" ); Abc_Print( -2, "\t writes the current AIG into the AIGER file\n" ); Abc_Print( -2, "\t-u : toggle writing canonical AIG structure [default = %s]\n", fUnique? "yes" : "no" ); Abc_Print( -2, "\t-p : toggle writing Verilog with 'and' and 'not' [default = %s]\n", fVerilog? "yes" : "no" ); @@ -32153,6 +32157,7 @@ int Abc_CommandAbc9Write( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -2, "\t-m : toggle writing MiniAIG rather than AIGER [default = %s]\n", fMiniAig? "yes" : "no" ); Abc_Print( -2, "\t-l : toggle writing MiniLUT rather than AIGER [default = %s]\n", fMiniLut? "yes" : "no" ); Abc_Print( -2, "\t-n : toggle writing \'\\n\' after \'c\' in the AIGER file [default = %s]\n", fWriteNewLine? "yes": "no" ); + Abc_Print( -2, "\t-r : toggle reversing the order of input/output bits [default = %s]\n", fReverse? "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"); Abc_Print( -2, "\t : the file name\n"); From 5fa9192412042b3db37cae4059555767994ab267 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 18 Jan 2024 18:34:50 -0800 Subject: [PATCH 67/67] Change how &stochsyn runs on a single core. --- src/aig/gia/giaStoch.c | 73 ++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/src/aig/gia/giaStoch.c b/src/aig/gia/giaStoch.c index 78fe2cb677..fc65c80bb7 100644 --- a/src/aig/gia/giaStoch.c +++ b/src/aig/gia/giaStoch.c @@ -60,28 +60,35 @@ ABC_NAMESPACE_IMPL_START SeeAlso [] ***********************************************************************/ -Gia_Man_t * Gia_StochProcessOne( Gia_Man_t * p, char * pScript, int Rand, int TimeSecs ) +Gia_Man_t * Gia_StochProcessSingle( Gia_Man_t * p, char * pScript, int Rand, int TimeSecs ) { - Gia_Man_t * pNew; - char FileName[100], Command[1000]; - sprintf( FileName, "%06x.aig", Rand ); - Gia_AigerWrite( p, FileName, 0, 0, 0 ); - sprintf( Command, "./abc -q \"&read %s; %s; &write %s\"", FileName, pScript, FileName ); - if ( system( (char *)Command ) ) + Gia_Man_t * pTemp, * pNew = Gia_ManDup( p ); + Abc_FrameUpdateGia( Abc_FrameGetGlobalFrame(), Gia_ManDup(p) ); + if ( Abc_FrameIsBatchMode() ) { - fprintf( stderr, "The following command has returned non-zero exit status:\n" ); - fprintf( stderr, "\"%s\"\n", (char *)Command ); - fprintf( stderr, "Sorry for the inconvenience.\n" ); - fflush( stdout ); - unlink( FileName ); - return Gia_ManDup(p); - } - pNew = Gia_AigerRead( FileName, 0, 0, 0 ); - unlink( FileName ); - if ( pNew && Gia_ManAndNum(pNew) < Gia_ManAndNum(p) ) - return pNew; - Gia_ManStopP( &pNew ); - return Gia_ManDup(p); + if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), pScript) ) + { + Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pScript ); + return NULL; + } + } + else + { + Abc_FrameSetBatchMode( 1 ); + if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), pScript) ) + { + Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pScript ); + return NULL; + } + Abc_FrameSetBatchMode( 0 ); + } + pTemp = Abc_FrameReadGia(Abc_FrameGetGlobalFrame()); + if ( Gia_ManAndNum(pNew) > Gia_ManAndNum(pTemp) ) + { + Gia_ManStop( pNew ); + pNew = Gia_ManDup( pTemp ); + } + return pNew; } void Gia_StochProcessArray( Vec_Ptr_t * vGias, char * pScript, int TimeSecs, int fVerbose ) { @@ -92,7 +99,7 @@ void Gia_StochProcessArray( Vec_Ptr_t * vGias, char * pScript, int TimeSecs, int Vec_IntPush( vRands, Abc_Random(0) % 0x1000000 ); Vec_PtrForEachEntry( Gia_Man_t *, vGias, pGia, i ) { - pNew = Gia_StochProcessOne( pGia, pScript, Vec_IntEntry(vRands, i), TimeSecs ); + pNew = Gia_StochProcessSingle( pGia, pScript, Vec_IntEntry(vRands, i), TimeSecs ); Gia_ManStop( pGia ); Vec_PtrWriteEntry( vGias, i, pNew ); } @@ -131,6 +138,30 @@ typedef struct Gia_StochThData_t_ int fWorking; } Gia_StochThData_t; +Gia_Man_t * Gia_StochProcessOne( Gia_Man_t * p, char * pScript, int Rand, int TimeSecs ) +{ + Gia_Man_t * pNew; + char FileName[100], Command[1000]; + sprintf( FileName, "%06x.aig", Rand ); + Gia_AigerWrite( p, FileName, 0, 0, 0 ); + sprintf( Command, "./abc -q \"&read %s; %s; &write %s\"", FileName, pScript, FileName ); + if ( system( (char *)Command ) ) + { + fprintf( stderr, "The following command has returned non-zero exit status:\n" ); + fprintf( stderr, "\"%s\"\n", (char *)Command ); + fprintf( stderr, "Sorry for the inconvenience.\n" ); + fflush( stdout ); + unlink( FileName ); + return Gia_ManDup(p); + } + pNew = Gia_AigerRead( FileName, 0, 0, 0 ); + unlink( FileName ); + if ( pNew && Gia_ManAndNum(pNew) < Gia_ManAndNum(p) ) + return pNew; + Gia_ManStopP( &pNew ); + return Gia_ManDup(p); +} + void * Gia_StochWorkerThread( void * pArg ) { Gia_StochThData_t * pThData = (Gia_StochThData_t *)pArg;