From 9b0786fe89795b026c1414677089ecc057624fcd Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 27 Nov 2025 19:46:16 -0800 Subject: [PATCH] Experiments with multipliers. --- src/aig/gia/gia.h | 2 + src/aig/gia/giaCut.c | 6 +- src/aig/gia/giaDup.c | 58 ++++++++++ src/aig/gia/giaMulFind.c | 51 ++++++-- src/misc/util/module.make | 1 + src/misc/util/utilMulSim.c | 230 +++++++++++++++++++++++++++++++++++++ src/misc/vec/vecInt.h | 6 +- 7 files changed, 338 insertions(+), 16 deletions(-) create mode 100644 src/misc/util/utilMulSim.c diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index 0799a0c96..efc85813b 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -1419,6 +1419,8 @@ typedef struct Gia_ChMan_t_ Gia_ChMan_t; extern Gia_ChMan_t * Gia_ManDupChoicesStart( Gia_Man_t * pGia ); extern void Gia_ManDupChoicesAdd( Gia_ChMan_t * pMan, Gia_Man_t * pGia ); extern Gia_Man_t * Gia_ManDupChoicesFinish( Gia_ChMan_t * pMan ); +extern Vec_Int_t * Gia_ManComputeMffc( Gia_Man_t * p, Vec_Int_t * vLits, Vec_Int_t * vOuts ); +extern Gia_Man_t * Gia_ManDupExtractMffc( Gia_Man_t * p, Vec_Int_t * vLits, Vec_Int_t * vAnds, Vec_Int_t * vCos ); /*=== giaEdge.c ==========================================================*/ extern void Gia_ManEdgeFromArray( Gia_Man_t * p, Vec_Int_t * vArray ); extern Vec_Int_t * Gia_ManEdgeToArray( Gia_Man_t * p ); diff --git a/src/aig/gia/giaCut.c b/src/aig/gia/giaCut.c index 35e3c34ee..5efc358ff 100644 --- a/src/aig/gia/giaCut.c +++ b/src/aig/gia/giaCut.c @@ -292,8 +292,8 @@ static inline int Gia_CutCompare2( Gia_Cut_t * pCut0, Gia_Cut_t * pCut1 ) } static inline int Gia_CutCompare( Gia_Cut_t * pCut0, Gia_Cut_t * pCut1 ) { - if ( pCut0->CostF > pCut1->CostF ) return -1; - if ( pCut0->CostF < pCut1->CostF ) return 1; + if ( pCut0->CostF > pCut1->CostF ) return -1; + if ( pCut0->CostF < pCut1->CostF ) return 1; if ( pCut0->nLeaves < pCut1->nLeaves ) return -1; if ( pCut0->nLeaves > pCut1->nLeaves ) return 1; return 0; @@ -1230,7 +1230,7 @@ void Gia_ManComputeCutsCore( Gia_Man_t * pGia, int nCutSize, int nCutNum, int fT Vec_Wec_t * Gia_ManCompute54Cuts( Gia_Man_t * pGia, int fVerbose ) { - Gia_Sto_t * pSto = Gia_ManMatchCutsInt( pGia, 5, 16, 0, fVerbose ); + Gia_Sto_t * pSto = Gia_ManMatchCutsInt( pGia, 5, 8, 0, fVerbose ); Vec_Wec_t * vRes = Vec_WecAlloc( 1000 ); Vec_Int_t * vLevel; int i, k, c, * pCut; Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { diff --git a/src/aig/gia/giaDup.c b/src/aig/gia/giaDup.c index c88ec06e7..2b4a0199f 100644 --- a/src/aig/gia/giaDup.c +++ b/src/aig/gia/giaDup.c @@ -6609,6 +6609,64 @@ Gia_Man_t * Gia_ManDupChoicesFinish( Gia_ChMan_t * p ) return pTemp; } +/**Function************************************************************* + + Synopsis [Extracting MFFC of the nodes supported by a set of literals.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +// collecting internal nodes and outputs in the MFF of a given set of literals +Vec_Int_t * Gia_ManComputeMffc( Gia_Man_t * p, Vec_Int_t * vLits, Vec_Int_t * vOuts ) +{ + Vec_Int_t * vTfo = Vec_IntAlloc( 100 ); + Gia_Obj_t * pObj; int i, Lit; + Vec_IntClear( vOuts ); + Gia_ManIncrementTravId( p ); + Vec_IntForEachEntry( vLits, Lit, i ) + Gia_ObjSetTravIdCurrentId( p, Abc_Lit2Var(Lit) ); + Gia_ManForEachAnd( p, pObj, i ) { + if ( Gia_ObjIsTravIdCurrentId(p, i) ) + continue; + if ( Gia_ObjIsTravIdCurrentId(p, Gia_ObjFaninId0(pObj, i)) && Gia_ObjIsTravIdCurrentId(p, Gia_ObjFaninId1(pObj, i)) ) + Gia_ObjSetTravIdCurrentId( p, i ), Vec_IntPush( vTfo, i ); + else if ( Gia_ObjIsTravIdCurrentId(p, Gia_ObjFaninId0(pObj, i)) ) + Vec_IntPushUniqueOrder( vOuts, Gia_ObjFaninId0(pObj, i) ); + else if ( Gia_ObjIsTravIdCurrentId(p, Gia_ObjFaninId1(pObj, i)) ) + Vec_IntPushUniqueOrder( vOuts, Gia_ObjFaninId1(pObj, i) ); + } + Gia_ManForEachCo( p, pObj, i ) + if ( Gia_ObjIsTravIdCurrentId(p, Gia_ObjFaninId0p(p, pObj)) ) + Vec_IntPushUniqueOrder( vOuts, Gia_ObjFaninId0p(p, pObj) ); + Vec_IntTwoFilter( vOuts, vTfo ); + return vTfo; +} + +// extracting the AIG of the MFFC defined by a given set of literals +Gia_Man_t * Gia_ManDupExtractMffc( Gia_Man_t * p, Vec_Int_t * vLits, Vec_Int_t * vAnds, Vec_Int_t * vCos ) +{ + Gia_Man_t * pNew; + Gia_Obj_t * pObj; + int i, Lit; + pNew = Gia_ManStart( 5000 ); + pNew->pName = Abc_UtilStrsav( p->pName ); + pNew->pSpec = Abc_UtilStrsav( p->pSpec ); + pNew->fGiaSimple = 1; + Gia_ManConst0(p)->Value = 0; + Vec_IntForEachEntry( vLits, Lit, i ) + Gia_ManObj(p, Abc_Lit2Var(Lit))->Value = Abc_LitNotCond( Gia_ManAppendCi(pNew), Abc_LitIsCompl(Lit) ); + Gia_ManForEachObjVec( vAnds, p, pObj, i ) + pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + Gia_ManForEachObjVec( vCos, p, pObj, i ) + pObj->Value = Gia_ManAppendCo( pNew, pObj->Value ); + return pNew; +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/aig/gia/giaMulFind.c b/src/aig/gia/giaMulFind.c index 9a6df208c..3dd454194 100644 --- a/src/aig/gia/giaMulFind.c +++ b/src/aig/gia/giaMulFind.c @@ -726,8 +726,16 @@ Vec_Wrd_t * Gia_ManMulFindSim( Vec_Wrd_t * vSim0, Vec_Wrd_t * vSim1, int fSigned } return vRes; } -void Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fLits, int fVerbose ) +Vec_Wrd_t * Gia_ManMulFindSim2( Vec_Wrd_t * vSim0, Vec_Wrd_t * vSim1, int fSigned ) { + extern word * product_many(word *pInfo1, int nBits1, word *pInfo2, int nBits2, int fSigned ); + word * pRes = product_many( Vec_WrdArray(vSim0), Vec_WrdSize(vSim0), Vec_WrdArray(vSim1), Vec_WrdSize(vSim1), fSigned ); + return Vec_WrdAllocArray( pRes, Vec_WrdSize(vSim0) + Vec_WrdSize(vSim1) ); +} +int Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fLits, int fVerbose ) +{ + //abctime clkTotal = Abc_Clock(); + int nDetected = 0; Abc_Random(1); for ( int m = 0; m < Vec_WecSize(vTerms)/3; m++ ) { Vec_Int_t * vIn0 = Vec_WecEntry(vTerms, 3*m+0); @@ -735,8 +743,8 @@ void Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fLits, int fV Vec_Int_t * vOut = Vec_WecEntry(vTerms, 3*m+2); Vec_Wrd_t * vSim0 = Vec_WrdStartRandom( Vec_IntSize(vIn0) ); Vec_Wrd_t * vSim1 = Vec_WrdStartRandom( Vec_IntSize(vIn1) ); - Vec_Wrd_t * vSimU = Gia_ManMulFindSim( vSim0, vSim1, 0 ); - Vec_Wrd_t * vSimS = Gia_ManMulFindSim( vSim0, vSim1, 1 ); + Vec_Wrd_t * vSimU = Gia_ManMulFindSim2( vSim0, vSim1, 0 ); + Vec_Wrd_t * vSimS = Gia_ManMulFindSim2( vSim0, vSim1, 1 ); Vec_Int_t * vTfo = Gia_ManMulFindTfo( p, vIn0, vIn1, fLits ); Vec_Wrd_t * vSims = Gia_ManMulFindSimCone( p, vIn0, vIn1, vSim0, vSim1, vTfo, fLits ); Vec_Int_t * vOutU = Vec_IntAlloc( 100 ); @@ -762,10 +770,14 @@ void Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fLits, int fV if ( Vec_IntCountEntry(vOutU, -1) < Vec_IntSize(vOutU) || Vec_IntCountEntry(vOutS, -1) < Vec_IntSize(vOutS) ) { - if ( Vec_IntCountEntry(vOutU, -1) < Vec_IntCountEntry(vOutS, -1) ) + if ( Vec_IntCountEntry(vOutU, -1) < Vec_IntCountEntry(vOutS, -1) ) { Vec_IntAppend( vOut, vOutU ), Vec_IntPush(vOut, 0); - else + nDetected = Vec_IntSize(vOutU) - Vec_IntCountEntry(vOutU, -1); + } + else { Vec_IntAppend( vOut, vOutS ), Vec_IntPush(vOut, 1); + nDetected = Vec_IntSize(vOutS) - Vec_IntCountEntry(vOutS, -1); + } } else { @@ -782,6 +794,8 @@ void Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fLits, int fV Vec_IntFree( vOutS ); } Vec_WecRemoveEmpty( vTerms ); + //Abc_PrintTime( 1, "Output detection time", Abc_Clock() - clkTotal ); + return nDetected; } /**Function************************************************************* @@ -831,11 +845,28 @@ void Gia_ManMulFindPrintSet( Vec_Int_t * vSet, int fLit, int fSkipLast ) { int i, Temp, Limit = Vec_IntSize(vSet) - fSkipLast; printf( "{" ); - Vec_IntForEachEntryStop( vSet, Temp, i, Limit ) { - if ( Temp == -1 ) - printf( "n/a%s", i < Limit-1 ? " ":"" ); - else - printf( "%s%d%s", (fLit & Abc_LitIsCompl(Temp)) ? "~":"", fLit ? Abc_Lit2Var(Temp) : Temp, i < Limit-1 ? " ":"" ); + if ( Vec_IntSize(vSet) > 16 ) { + Vec_IntForEachEntryStop( vSet, Temp, i, 4 ) { + if ( Temp == -1 ) + printf( "n/a%s", i < Limit-1 ? " ":"" ); + else + printf( "%s%d%s", (fLit & Abc_LitIsCompl(Temp)) ? "~":"", fLit ? Abc_Lit2Var(Temp) : Temp, i < Limit-1 ? " ":"" ); + } + printf( "... " ); + Vec_IntForEachEntryStartStop( vSet, Temp, i, Limit-4, Limit ) { + if ( Temp == -1 ) + printf( "n/a%s", i < Limit-1 ? " ":"" ); + else + printf( "%s%d%s", (fLit & Abc_LitIsCompl(Temp)) ? "~":"", fLit ? Abc_Lit2Var(Temp) : Temp, i < Limit-1 ? " ":"" ); + } + } + else { + Vec_IntForEachEntryStop( vSet, Temp, i, Limit ) { + if ( Temp == -1 ) + printf( "n/a%s", i < Limit-1 ? " ":"" ); + else + printf( "%s%d%s", (fLit & Abc_LitIsCompl(Temp)) ? "~":"", fLit ? Abc_Lit2Var(Temp) : Temp, i < Limit-1 ? " ":"" ); + } } printf( "}" ); } diff --git a/src/misc/util/module.make b/src/misc/util/module.make index 991f6f311..205e2a734 100644 --- a/src/misc/util/module.make +++ b/src/misc/util/module.make @@ -7,6 +7,7 @@ SRC += src/misc/util/utilBridge.c \ src/misc/util/utilIsop.c \ src/misc/util/utilLinear.c \ src/misc/util/utilMiniver.c \ + src/misc/util/utilMulSim.c \ src/misc/util/utilNam.c \ src/misc/util/utilPrefix.cpp \ src/misc/util/utilPth.c \ diff --git a/src/misc/util/utilMulSim.c b/src/misc/util/utilMulSim.c new file mode 100644 index 000000000..d5542e519 --- /dev/null +++ b/src/misc/util/utilMulSim.c @@ -0,0 +1,230 @@ +/**CFile**************************************************************** + + FileName [utilMulSim.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Generating multiplier simulation info.] + + Synopsis [Generating multiplier simulation info.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - Feburary 13, 2011.] + + Revision [$Id: utilMulSim.c,v 1.00 2011/02/11 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include +#include +#include +#include +#include +#include "misc/util/abc_global.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +#define SIG_WIDTH 64 // 64 simulation patterns in each signature word + +// ---------------------------------------------------------------------- +// Core 32-bit-limb big integer unsigned multiply +// ---------------------------------------------------------------------- + +uint32_t * product(const uint32_t *pArg1, int nInts1, + const uint32_t *pArg2, int nInts2) +{ + assert( pArg1 && pArg2 && nInts1 > 0 && nInts2 > 0 ); + int nRes = nInts1 + nInts2; + uint32_t *pRes = (uint32_t *)calloc((size_t)nRes, sizeof(uint32_t)); + if (!pRes) return NULL; + // Schoolbook multiplication in base 2^32 + for (int i = 0; i < nInts1; ++i) { + uint64_t a = pArg1[i]; + if (a == 0) continue; + uint64_t carry = 0; + for (int j = 0; j < nInts2; ++j) { + uint64_t t = (uint64_t)pRes[i + j] + a * (uint64_t)pArg2[j] + carry; + pRes[i + j] = (uint32_t)t; + carry = t >> 32; + } + pRes[i + nInts2] = (uint32_t)carry; + } + return pRes; +} + +// ---------------------------------------------------------------------- +// Bit-matrix helpers: signatures <-> per-pattern 32-bit-limb big ints +// ---------------------------------------------------------------------- + +static void transpose_signatures_to_pattern(const uint64_t *sigs, + int nBits, + uint32_t *dst, + int nInts, + int patternIdx) +{ + memset(dst, 0, (size_t)nInts * sizeof(uint32_t)); + for (int bit = 0; bit < nBits; ++bit) { + uint64_t sigWord = sigs[bit]; + uint64_t bitVal = (sigWord >> patternIdx) & 1ULL; + if (!bitVal) continue; + int word = bit / 32; + int offset = bit & 31; + dst[word] |= (uint32_t)(1u << offset); + } +} + +static void transpose_pattern_to_signatures(const uint32_t *src, + int nIntsRes, + int nBitsRes, + uint64_t *outSigs, + int patternIdx) +{ + for (int bit = 0; bit < nBitsRes; ++bit) { + int word = bit / 32; + int offset = bit & 31; + if (word >= nIntsRes) + break; + uint32_t bitVal = (src[word] >> offset) & 1u; + if (bitVal) + outSigs[bit] |= (uint64_t)1ULL << patternIdx; + } +} + +// ---------------------------------------------------------------------- +// Signed helpers for 32-bit-limb big ints (two's complement on nBits) +// ---------------------------------------------------------------------- + +static int is_negative(const uint32_t *x, int nBits) +{ + int bitPos = nBits - 1; + int word = bitPos / 32; + int offset = bitPos & 31; + return (x[word] >> offset) & 1u; +} + +static void mask_to_nBits(uint32_t *x, int nInts, int nBits) +{ + if (nBits <= 0) { + for (int i = 0; i < nInts; ++i) + x[i] = 0; + return; + } + int lastWord = (nBits - 1) / 32; // index of last used word + int usedBitsInLast = nBits - lastWord * 32; // 1..32 + // Zero any words above the last used word + for (int i = lastWord + 1; i < nInts; ++i) + x[i] = 0; + // If nBits is not a multiple of 32, mask off the high bits of last word + if (usedBitsInLast < 32) { + uint32_t mask = ((uint32_t)1u << usedBitsInLast) - 1u; + x[lastWord] &= mask; + } +} + +static void twos_complement_inplace(uint32_t *x, int nInts, int nBits) +{ + // Invert + for (int i = 0; i < nInts; ++i) + x[i] = ~x[i]; + mask_to_nBits(x, nInts, nBits); + // Add 1 + uint64_t carry = 1; + for (int i = 0; i < nInts; ++i) { + uint64_t sum = (uint64_t)x[i] + carry; + x[i] = (uint32_t)sum; + carry = sum >> 32; + if (!carry) + break; + } + mask_to_nBits(x, nInts, nBits); +} + +// ---------------------------------------------------------------------- +// product_many: unsigned and signed (two's-complement) versions +// ---------------------------------------------------------------------- + +uint64_t * product_many_unsigned(uint64_t *pInfo1, int nBits1, + uint64_t *pInfo2, int nBits2) +{ + assert( pInfo1 && pInfo2 && nBits1 > 0 && nBits2 > 0 ); + int nInts1 = (nBits1 + 31) / 32; + int nInts2 = (nBits2 + 31) / 32; + int nBitsRes = nBits1 + nBits2; + int nIntsRes = nInts1 + nInts2; + uint64_t *outSigs = (uint64_t *)calloc((size_t)nBitsRes, sizeof(uint64_t)); + if (!outSigs) return NULL; + uint32_t *tmp1 = (uint32_t *)calloc((size_t)nInts1, sizeof(uint32_t)); + uint32_t *tmp2 = (uint32_t *)calloc((size_t)nInts2, sizeof(uint32_t)); + assert( tmp1 && tmp2 ); + for (int pattern = 0; pattern < SIG_WIDTH; ++pattern) { + transpose_signatures_to_pattern(pInfo1, nBits1, tmp1, nInts1, pattern); + transpose_signatures_to_pattern(pInfo2, nBits2, tmp2, nInts2, pattern); + uint32_t *tmpRes = product(tmp1, nInts1, tmp2, nInts2); assert( tmpRes ); + transpose_pattern_to_signatures(tmpRes, nIntsRes, nBitsRes, outSigs, pattern); + free(tmpRes); + } + free(tmp1); + free(tmp2); + return outSigs; +} + +uint64_t * product_many_signed(uint64_t *pInfo1, int nBits1, + uint64_t *pInfo2, int nBits2) +{ + assert( pInfo1 && pInfo2 && nBits1 > 0 && nBits2 > 0 ); + int nInts1 = (nBits1 + 31) / 32; + int nInts2 = (nBits2 + 31) / 32; + int nBitsRes = nBits1 + nBits2; + int nIntsRes = nInts1 + nInts2; + uint64_t *outSigs = (uint64_t *)calloc((size_t)nBitsRes, sizeof(uint64_t)); + if (!outSigs) return NULL; + uint32_t *op1 = (uint32_t *)calloc((size_t)nInts1, sizeof(uint32_t)); + uint32_t *op2 = (uint32_t *)calloc((size_t)nInts2, sizeof(uint32_t)); + assert( op1 && op2 ); + for (int pattern = 0; pattern < SIG_WIDTH; ++pattern) { + transpose_signatures_to_pattern(pInfo1, nBits1, op1, nInts1, pattern); + transpose_signatures_to_pattern(pInfo2, nBits2, op2, nInts2, pattern); + int neg1 = is_negative(op1, nBits1); + int neg2 = is_negative(op2, nBits2); + int negRes = neg1 ^ neg2; + if (neg1) twos_complement_inplace(op1, nInts1, nBits1); + if (neg2) twos_complement_inplace(op2, nInts2, nBits2); + uint32_t *tmpRes = product(op1, nInts1, op2, nInts2); assert( tmpRes ); + if (negRes) + twos_complement_inplace(tmpRes, nIntsRes, nBitsRes); + else + mask_to_nBits(tmpRes, nIntsRes, nBitsRes); + transpose_pattern_to_signatures(tmpRes, nIntsRes, nBitsRes, outSigs, pattern); + free(tmpRes); + } + free(op1); + free(op2); + return outSigs; +} + +word * product_many(word *pInfo1, int nBits1, word *pInfo2, int nBits2, int fSigned ) +{ + if ( fSigned ) + return (word *)product_many_signed((uint64_t *)pInfo1, nBits1, (uint64_t *)pInfo2, nBits2); + else + return (word *)product_many_unsigned((uint64_t *)pInfo1, nBits1, (uint64_t *)pInfo2, nBits2); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/misc/vec/vecInt.h b/src/misc/vec/vecInt.h index a03cd30b8..e32a2dd18 100644 --- a/src/misc/vec/vecInt.h +++ b/src/misc/vec/vecInt.h @@ -1947,16 +1947,16 @@ static inline int Vec_IntTwoRemove( Vec_Int_t * vArr1, Vec_Int_t * vArr2 ) /**Function************************************************************* - Synopsis [Returns the result of merging the two vectors.] + Synopsis [Keeps only those entries in vArr1, which are in vArr2.] - Description [Keeps only those entries of vArr1, which are in vArr2.] + Description [Assumes that the vectors are sorted in the increasing order.] SideEffects [] SeeAlso [] ***********************************************************************/ -static inline void Vec_IntTwoMerge1( Vec_Int_t * vArr1, Vec_Int_t * vArr2 ) +static inline void Vec_IntTwoFilter( Vec_Int_t * vArr1, Vec_Int_t * vArr2 ) { int * pBeg = vArr1->pArray; int * pBeg1 = vArr1->pArray;