diff --git a/abclib.dsp b/abclib.dsp index 4e027c495..db504b712 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -5211,6 +5211,10 @@ SOURCE=.\src\aig\gia\giaRex.c # End Source File # Begin Source File +SOURCE=.\src\aig\gia\giaRrr.cpp +# End Source File +# Begin Source File + SOURCE=.\src\aig\gia\giaSat3.c # End Source File # Begin Source File diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index 015a1da22..09e892160 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -1806,6 +1806,9 @@ extern Gia_Man_t * Gia_ManTtoptCare( Gia_Man_t * p, int nIns, int nOuts, extern Gia_Man_t * Gia_ManTransductionBdd( Gia_Man_t * pGia, int nType, int fMspf, int nRandom, int nSortType, int nPiShuffle, int nParameter, int fLevel, Gia_Man_t * pExdc, int fNewLine, int nVerbose ); extern Gia_Man_t * Gia_ManTransductionTt( Gia_Man_t * pGia, int nType, int fMspf, int nRandom, int nSortType, int nPiShuffle, int nParameter, int fLevel, Gia_Man_t * pExdc, int fNewLine, int nVerbose ); +/*=== giaRrr.cpp ===========================================================*/ +extern Gia_Man_t * Gia_ManRrr( Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow ); + /*=== giaCTas.c ===========================================================*/ typedef struct Tas_Man_t_ Tas_Man_t; extern Tas_Man_t * Tas_ManAlloc( Gia_Man_t * pAig, int nBTLimit ); diff --git a/src/aig/gia/giaRrr.cpp b/src/aig/gia/giaRrr.cpp new file mode 100644 index 000000000..21e343337 --- /dev/null +++ b/src/aig/gia/giaRrr.cpp @@ -0,0 +1,31 @@ +#include "aig/gia/gia.h" + +#include "opt/rrr/rrr.h" +#include "opt/rrr/rrrAbc.h" + +ABC_NAMESPACE_IMPL_START + +Gia_Man_t *Gia_ManRrr(Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow) { + rrr::AndNetwork ntk; + ntk.Read(pGia, rrr::GiaReader); + rrr::Parameter Par; + Par.iSeed = iSeed; + Par.nWords = nWords; + Par.nTimeout = nTimeout; + Par.nSchedulerVerbose = nSchedulerVerbose; + Par.nOptimizerVerbose = nOptimizerVerbose; + Par.nAnalyzerVerbose = nAnalyzerVerbose; + Par.nSimulatorVerbose = nSimulatorVerbose; + Par.nSatSolverVerbose = nSatSolverVerbose; + Par.fUseBddCspf = fUseBddCspf; + Par.fUseBddMspf = fUseBddMspf; + Par.nConflictLimit = nConflictLimit; + Par.nSortType = nSortType; + Par.nOptimizerFlow = nOptimizerFlow; + Par.nSchedulerFlow = nSchedulerFlow; + rrr::Perform(&ntk, &Par); + Gia_Man_t *pNew = rrr::CreateGia(&ntk); + return pNew; +} + +ABC_NAMESPACE_IMPL_END diff --git a/src/aig/gia/module.make b/src/aig/gia/module.make index 27240f443..2e64d1d1b 100644 --- a/src/aig/gia/module.make +++ b/src/aig/gia/module.make @@ -73,6 +73,7 @@ SRC += src/aig/gia/giaAig.c \ src/aig/gia/giaResub6.c \ src/aig/gia/giaRetime.c \ src/aig/gia/giaRex.c \ + src/aig/gia/giaRrr.cpp \ src/aig/gia/giaSatEdge.c \ src/aig/gia/giaSatLE.c \ src/aig/gia/giaSatLut.c \ @@ -111,4 +112,4 @@ SRC += src/aig/gia/giaAig.c \ src/aig/gia/giaTtopt.cpp \ src/aig/gia/giaUnate.c \ src/aig/gia/giaUtil.c \ - src/aig/gia/giaBound.c \ No newline at end of file + src/aig/gia/giaBound.c diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index ff1fa79fd..9d4ef58bf 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -521,6 +521,7 @@ static int Abc_CommandAbc9LNetOpt ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9Ttopt ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Transduction ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9TranStoch ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Rrr ( Abc_Frame_t * pAbc, int argc, char ** argv ); //#endif static int Abc_CommandAbc9LNetMap ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Unmap ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1323,6 +1324,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&ttopt", Abc_CommandAbc9Ttopt, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&transduction", Abc_CommandAbc9Transduction, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&transtoch" , Abc_CommandAbc9TranStoch, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&rrr", Abc_CommandAbc9Rrr, 0 ); //#endif Cmd_CommandAdd( pAbc, "ABC9", "&lnetmap", Abc_CommandAbc9LNetMap, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&unmap", Abc_CommandAbc9Unmap, 0 ); @@ -45112,6 +45114,132 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + Gia_Man_t *pNew; + int c; + int iSeed = 0, nWords = 10, nTimeout = 0, nSchedulerVerbose = 1, nOptimizerVerbose = 0, nAnalyzerVerbose = 0, nSimulatorVerbose = 0, nSatSolverVerbose = 0, fUseBddCspf = 0, fUseBddMspf = 0, nConflictLimit = 0, nSortType = 12, nOptimizerFlow = 0, nSchedulerFlow = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "XYRWTCGSOAPQabh" ) ) != EOF ) + { + switch ( c ) + { + case 'X': + nOptimizerFlow = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'Y': + nSchedulerFlow = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'R': + iSeed = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'W': + nWords = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'T': + nTimeout = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'C': + nConflictLimit = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'G': + nSortType = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'S': + nSchedulerVerbose = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'O': + nOptimizerVerbose = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'A': + nAnalyzerVerbose = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'P': + nSimulatorVerbose = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'Q': + nSatSolverVerbose = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'a': + fUseBddCspf ^= 1; + break; + case 'b': + fUseBddMspf ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + + if ( argc > globalUtilOptind ) { + Abc_Print( -1, "Wrong number of auguments.\n" ); + goto usage; + } + + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Empty GIA network.\n" ); + return 1; + } + + pNew = Gia_ManRrr( pAbc->pGia, iSeed, nWords, nTimeout, nSchedulerVerbose, nOptimizerVerbose, nAnalyzerVerbose, nSimulatorVerbose, nSatSolverVerbose, fUseBddCspf, fUseBddMspf, nConflictLimit, nSortType, nOptimizerFlow, nSchedulerFlow ); + + Abc_FrameUpdateGia( pAbc, pNew ); + + return 0; + +usage: + Abc_Print( -2, "usage: rrr [-XYRWTCGSOAPQ num] [-abh]\n" ); + Abc_Print( -2, "\t perform optimization\n" ); + Abc_Print( -2, "\t-X num : method [default = %d]\n", nOptimizerFlow ); + Abc_Print( -2, "\t 0: single-add resub\n" ); + Abc_Print( -2, "\t 1: multi-add resub\n" ); + Abc_Print( -2, "\t 2: repeat 0 and 1\n" ); + Abc_Print( -2, "\t-Y num : flow [default = %d]\n", nSchedulerFlow ); + Abc_Print( -2, "\t 0: apply method once\n" ); + Abc_Print( -2, "\t 1: iterate like transtoch\n" ); + Abc_Print( -2, "\t 2: iterate like deepsyn\n" ); + Abc_Print( -2, "\t-R num : random number generator seed [default = %d]\n", iSeed ); + Abc_Print( -2, "\t-W num : number of simulation words [default = %d]\n", nWords ); + Abc_Print( -2, "\t-T num : timeout in seconds (0 = no timeout) [default = %d]\n", nTimeout ); + Abc_Print( -2, "\t-C num : conflict limit [default = %d]\n", nConflictLimit ); + Abc_Print( -2, "\t-G num : fanin cost function [default = %d]\n", nSortType ); + Abc_Print( -2, "\t-S num : scheduler verbosity level [default = %d]\n", nSchedulerVerbose ); + Abc_Print( -2, "\t-O num : optimizer verbosity level [default = %d]\n", nOptimizerVerbose ); + Abc_Print( -2, "\t-A num : analyzer verbosity level [default = %d]\n", nAnalyzerVerbose ); + Abc_Print( -2, "\t-P num : simulator verbosity level [default = %d]\n", nSimulatorVerbose ); + Abc_Print( -2, "\t-Q num : SAT solver verbosity level [default = %d]\n", nSatSolverVerbose ); + Abc_Print( -2, "\t-a : use BDD-based analyzer (CSPF) [default = %s]\n", fUseBddCspf? "yes": "no" ); + Abc_Print( -2, "\t-b : use BDD-based analyzer (MSPF) [default = %s]\n", fUseBddMspf? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/opt/rrr/rrr.h b/src/opt/rrr/rrr.h new file mode 100644 index 000000000..d306da3af --- /dev/null +++ b/src/opt/rrr/rrr.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "rrrParameter.h" +#include "rrrTypes.h" +#include "rrrAndNetwork.h" +#include "rrrScheduler.h" +#include "rrrOptimizer.h" +#include "rrrAnalyzer.h" +#include "rrrBddAnalyzer.h" +#include "rrrBddMspfAnalyzer.h" +#include "rrrSatSolver.h" +#include "rrrSimulator.h" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace rrr { + + template + void Perform(Ntk *pNtk, Parameter const *pPar) { + assert(!pPar->fUseBddCspf || !pPar->fUseBddMspf); + if(pPar->fUseBddCspf) { + Scheduler>> sch(pNtk, pPar); + sch.Run(); + } else if(pPar->fUseBddMspf) { + Scheduler>> sch(pNtk, pPar); + sch.Run(); + } else { + Scheduler, rrr::SatSolver>>> sch(pNtk, pPar); + sch.Run(); + } + } + +} + +ABC_NAMESPACE_CXX_HEADER_END diff --git a/src/opt/rrr/rrrAbc.h b/src/opt/rrr/rrrAbc.h new file mode 100644 index 000000000..5fc2e1ff5 --- /dev/null +++ b/src/opt/rrr/rrrAbc.h @@ -0,0 +1,80 @@ +#pragma once + +#include + +#include "aig/gia/gia.h" +#include "base/main/main.h" +#include "base/cmd/cmd.h" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace rrr { + + template + void GiaReader(Gia_Man_t *pGia, Ntk *pNtk) { + int i; + Gia_Obj_t *pObj; + pNtk->Reserve(Gia_ManObjNum(pGia)); + Gia_ManConst0(pGia)->Value = pNtk->GetConst0(); + Gia_ManForEachObj1(pGia, pObj, i) { + if(Gia_ObjIsCi(pObj)) { + pObj->Value = pNtk->AddPi(); + } else if(Gia_ObjIsCo(pObj)) { + pNtk->AddPo(Gia_ObjFanin0(pObj)->Value, Gia_ObjFaninC0(pObj)); + } else { + // TODO: support XOR (and BUF and MUX?), maybe create another function + pObj->Value = pNtk->AddAnd(Gia_ObjFanin0(pObj)->Value, Gia_ObjFanin1(pObj)->Value, Gia_ObjFaninC0(pObj), Gia_ObjFaninC1(pObj)); + } + } + } + + template + Gia_Man_t *CreateGia(Ntk *pNtk) { + Gia_Man_t *pGia = Gia_ManStart(pNtk->GetNumNodes()); + Gia_ManHashStart(pGia); + std::vector v(pNtk->GetNumNodes()); + v[0] = Gia_ManConst0Lit(); + pNtk->ForEachPi([&](int id) { + v[id] = Gia_ManAppendCi(pGia); + }); + pNtk->ForEachInt([&](int id) { + assert(pNtk->GetNodeType(id) == rrr::AND); + int x = -1; + pNtk->ForEachFanin(id, [&](int fi, bool c) { + if(x == -1) { + x = Abc_LitNotCond(v[fi], c); + } else { + x = Gia_ManHashAnd(pGia, x, Abc_LitNotCond(v[fi], c)); + } + }); + if(x == -1) { + x = Abc_LitNot(v[0]); + } + v[id] = x; + }); + pNtk->ForEachPoDriver([&](int fi, bool c) { + Gia_ManAppendCo(pGia, Abc_LitNotCond(v[fi], c)); + }); + Gia_ManHashStop(pGia); + return pGia; + } + + template + void Abc9Execute(Ntk *pNtk, std::string Command) { + Abc_Frame_t *pAbc = Abc_FrameGetGlobalFrame(); + Abc_FrameUpdateGia(pAbc, CreateGia(pNtk)); + if(Abc_FrameIsBatchMode()) { + int r = Cmd_CommandExecute(pAbc, Command.c_str()); + assert(r == 0); + } else { + Abc_FrameSetBatchMode(1); + int r = Cmd_CommandExecute(pAbc, Command.c_str()); + assert(r == 0); + Abc_FrameSetBatchMode(0); + } + pNtk->Read(Abc_FrameReadGia(pAbc), GiaReader); + } + +} + +ABC_NAMESPACE_CXX_HEADER_END diff --git a/src/opt/rrr/rrrAnalyzer.h b/src/opt/rrr/rrrAnalyzer.h new file mode 100644 index 000000000..a01d811c7 --- /dev/null +++ b/src/opt/rrr/rrrAnalyzer.h @@ -0,0 +1,105 @@ +#pragma once + +#include + +#include "rrrParameter.h" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace rrr { + + template + class Analyzer { + private: + // pointer to network + Ntk *pNtk; + + // parameters + bool nVerbose; + + // data + Sim sim; + Sol sol; + + public: + // constructors + Analyzer(Ntk *pNtk, Parameter const *pPar); + void UpdateNetwork(Ntk *pNtk_, bool fSame); + + // checks + bool CheckRedundancy(int id, int idx); + bool CheckFeasibility(int id, int fi, bool c); + }; + + /* {{{ Constructors */ + + template + Analyzer::Analyzer(Ntk *pNtk, Parameter const *pPar) : + pNtk(pNtk), + nVerbose(pPar->nAnalyzerVerbose), + sim(pNtk, pPar), + sol(pNtk, pPar) { + } + + template + void Analyzer::UpdateNetwork(Ntk *pNtk_, bool fSame) { + pNtk = pNtk_; + sim.UpdateNetwork(pNtk, fSame); + sol.UpdateNetwork(pNtk, fSame); + } + + /* }}} */ + + /* {{{ Checks */ + + template + bool Analyzer::CheckRedundancy(int id, int idx) { + if(sim.CheckRedundancy(id, idx)) { + if(nVerbose) { + std::cout << "node " << id << " fanin " << (pNtk->GetCompl(id, idx)? "!": "") << pNtk->GetFanin(id, idx) << " index " << idx << " seems redundant" << std::endl; + } + SatResult r = sol.CheckRedundancy(id, idx); + if(r == UNSAT) { + if(nVerbose) { + std::cout << "node " << id << " fanin " << (pNtk->GetCompl(id, idx)? "!": "") << pNtk->GetFanin(id, idx) << " index " << idx << " is redundant" << std::endl; + } + return true; + } + if(r == SAT) { + if(nVerbose) { + std::cout << "node " << id << " fanin " << (pNtk->GetCompl(id, idx)? "!": "") << pNtk->GetFanin(id, idx) << " index " << idx << " is NOT redundant" << std::endl; + } + sim.AddCex(sol.GetCex()); + } + } + return false; + } + + template + bool Analyzer::CheckFeasibility(int id, int fi, bool c) { + if(sim.CheckFeasibility(id, fi, c)) { + if(nVerbose) { + std::cout << "node " << id << " fanin " << (c? "!": "") << fi << " seems feasible" << std::endl; + } + SatResult r = sol.CheckFeasibility(id, fi, c); + if(r == UNSAT) { + if(nVerbose) { + std::cout << "node " << id << " fanin " << (c? "!": "") << fi << " is feasible" << std::endl; + } + return true; + } + if(r == SAT) { + if(nVerbose) { + std::cout << "node " << id << " fanin " << (c? "!": "") << fi << " is NOT feasible" << std::endl; + } + sim.AddCex(sol.GetCex()); + } + } + return false; + } + + /* }}} */ + +} + +ABC_NAMESPACE_CXX_HEADER_END diff --git a/src/opt/rrr/rrrAndNetwork.h b/src/opt/rrr/rrrAndNetwork.h new file mode 100644 index 000000000..2d321186c --- /dev/null +++ b/src/opt/rrr/rrrAndNetwork.h @@ -0,0 +1,1132 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rrrParameter.h" +#include "rrrTypes.h" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace rrr { + + class AndNetwork { + private: + // aliases + using itr = std::list::iterator; + using citr = std::list::const_iterator; + using ritr = std::list::reverse_iterator; + using critr = std::list::const_reverse_iterator; + using Callback = std::function; + + // network data + int nNodes; // number of allocated nodes + std::vector vPis; + std::list lInts; // internal nodes in topological order + std::set sInts; // internal nodes as a set + std::vector vPos; + std::vector> vvFaninEdges; // complementable edges, no duplicated fanins allowed (including complements), and nodes without fanins are treated as const-1 + std::vector vRefs; // reference count (number of fanouts) + + // mark for network traversal + bool fLockTrav; + unsigned iTrav; + std::vector vTrav; + + // flag used during constant propagation + bool fPropagating; + + // callback functions + std::vector vCallbacks; + + // network backups + std::vector vBackups; + + // conversion between node and edge + int Node2Edge(int id, bool c) const { return (id << 1) + (int)c; } + int Edge2Node(int f) const { return f >> 1; } + bool EdgeIsCompl(int f) const { return f & 1; } + + // other private functions + int CreateNode(); + void SortInts(itr it); + void StartTraversal(); + void EndTraversal(); + void TakenAction(Action const &action) const; + + public: + // constructors + AndNetwork(); + AndNetwork(AndNetwork const &x); + AndNetwork &operator=(AndNetwork const &x); + + // initialization APIs (should not be called after optimization has started) + void Clear(); + void Reserve(int nReserve); + int AddPi(); + int AddPo(int id, bool c); + int AddAnd(int id0, int id1, bool c0, bool c1); + template + void Read(Ntk *pFrom, Reader &reader); + + // network properties + bool UseComplementedEdges() const; + int GetNumNodes() const; // number of allocated nodes (max id + 1) + int GetNumPis() const; + int GetNumInts() const; + int GetNumPos() const; + int GetConst0() const; + int GetPi(int idx) const; + std::vector GetPis() const; + std::vector GetInts() const; + std::vector GetPisInts() const; + std::vector GetPos() const; + + // node properties + bool IsPi(int id) const; + bool IsInt(int id) const; + bool IsPo(int id) const; + NodeType GetNodeType(int id) const; + bool IsPoDriver(int id) const; + int GetPiIndex(int id) const; + int GetIntIndex(int id) const; + int GetPoIndex(int id) const; + int GetNumFanins(int id) const; + int GetNumFanouts(int id) const; + int GetFanin(int id, int idx) const; + bool GetCompl(int id, int idx) const; + int FindFanin(int id, int fi) const; + bool IsReconvergent(int id); + + // network traversal + void ForEachPi(std::function const &func) const; + void ForEachInt(std::function const &func) const; + void ForEachIntReverse(std::function const &func) const; + void ForEachPo(std::function const &func) const; + void ForEachPoDriver(std::function const &func) const; + void ForEachFanin(int id, std::function const &func) const; + void ForEachFaninIdx(int id, std::function const &func) const; // func(fi, c, index of fi in fanin list of id) + void ForEachFanout(int id, bool fPos, std::function const &func) const; + void ForEachFanoutRidx(int id, bool fPos, std::function const &func) const; // func(fo, c, index of id in fanin list of fo) + void ForEachTfo(int id, bool fPos, std::function const &func); + void ForEachTfoReverse(int id, bool fPos, std::function const &func); + void ForEachTfoUpdate(int id, bool fPos, std::function const &func); + template