Skip to content

Commit 92b0ee5

Browse files
committed
Add per-node origin cap (nOriginsMax) to bound accumulation
Shared fanin cones can accumulate origins from all CO drivers, causing O(n²) dedup cost in Gia_ObjAddOrigin. Add nOriginsMax field to Gia_Man_t that short-circuits overflow-mode AddOrigin when the node has reached the limit. Cap is set via &origins_id -M. Pathological case (10K outputs, shared 50-deep cone): No cap: 5.70s, 1.01M total origins, max 10000/node -M 256: 0.79s, 45K total origins, max 256/node (7.2x faster) Normal designs (i10.aig, max 165/node): identical results. Co-developed-by: Claude Code v2.1.89 (claude-opus-4-6)
1 parent 4496674 commit 92b0ee5

3 files changed

Lines changed: 57 additions & 7 deletions

File tree

src/aig/gia/gia.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ struct Gia_Man_t_
220220
Vec_Int_t * vIdsEquiv; // original object IDs proved equivalent
221221
Vec_Int_t * vEquLitIds; // original object IDs proved equivalent
222222
Vec_Int_t * vOrigins; // per-object origin mapping (from "y" extension)
223+
int nOriginsMax; // max origins per object (0 = unlimited)
223224
Vec_Int_t * vCofVars; // cofactoring variables
224225
Vec_Vec_t * vClockDoms; // clock domains
225226
Vec_Flt_t * vTiming; // arrival/required/slack

src/aig/gia/giaDup.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ void Gia_ObjAddOrigin( Gia_Man_t * p, int iObj, int iOrig )
213213
e = Gia_ObjOriginsEntry( p, iObj );
214214
if ( Gia_ObjOriginsIsOverflow(e) )
215215
{
216+
// cap check: skip if at user-specified limit
217+
if ( p->nOriginsMax > 0 && e->large.count >= p->nOriginsMax )
218+
return;
216219
// overflow mode: check for duplicate
217220
for ( k = 0; k < e->large.count; k++ )
218221
if ( e->large.overflow[k] == iOrig ) return;
@@ -331,6 +334,7 @@ void Gia_ManOriginsDup( Gia_Man_t * pNew, Gia_Man_t * pOld )
331334
if ( !pOld->vOrigins )
332335
return;
333336
Gia_ManOriginsReset( pNew );
337+
pNew->nOriginsMax = pOld->nOriginsMax;
334338
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
335339
Gia_ManForEachObj( pOld, pObj, i )
336340
{
@@ -364,6 +368,7 @@ void Gia_ManOriginsDupVec( Gia_Man_t * pNew, Gia_Man_t * pOld, Vec_Int_t * vCopi
364368
if ( !pOld->vOrigins )
365369
return;
366370
Gia_ManOriginsReset( pNew );
371+
pNew->nOriginsMax = pOld->nOriginsMax;
367372
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
368373
Vec_IntForEachEntry( vCopies, iLit, i )
369374
{
@@ -399,6 +404,7 @@ void Gia_ManOriginsAfterRoundTrip( Gia_Man_t * pNew, Gia_Man_t * pOld )
399404
assert( Gia_ManCiNum(pNew) == Gia_ManCiNum(pOld) );
400405
assert( Gia_ManCoNum(pNew) == Gia_ManCoNum(pOld) );
401406
Gia_ManOriginsReset( pNew );
407+
pNew->nOriginsMax = pOld->nOriginsMax;
402408
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
403409
// const0
404410
Gia_ObjUnionOrigins( pNew, 0, pOld, 0 );
@@ -456,6 +462,7 @@ void Gia_ManOriginsDupIf( Gia_Man_t * pNew, Gia_Man_t * p, void * pIfManVoid )
456462
if ( !p->vOrigins )
457463
return;
458464
Gia_ManOriginsReset( pNew );
465+
pNew->nOriginsMax = p->nOriginsMax;
459466
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
460467
If_ManForEachObj( pIfMan, pIfObj, i )
461468
{
@@ -1108,6 +1115,7 @@ Gia_Man_t * Gia_ManDupWithAttributes( Gia_Man_t * p )
11081115
if ( p->pCellStr )
11091116
pNew->pCellStr = Abc_UtilStrsav( p->pCellStr );
11101117
// copy origins if present (deep-copy overflow arrays)
1118+
pNew->nOriginsMax = p->nOriginsMax;
11111119
if ( p->vOrigins )
11121120
{
11131121
int iObj, nObjs;

src/base/abci/abc.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35536,12 +35536,27 @@ int Abc_CommandAbc9Ps( Abc_Frame_t * pAbc, int argc, char ** argv )
3553635536
int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3553735537
{
3553835538
Gia_Man_t * pGia = pAbc->pGia;
35539-
int c;
35539+
int c, fSetCap = 0, nOriginsMax = 0;
3554035540
Extra_UtilGetoptReset();
35541-
while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF )
35541+
while ( ( c = Extra_UtilGetopt( argc, argv, "Mh" ) ) != EOF )
3554235542
{
3554335543
switch ( c )
3554435544
{
35545+
case 'M':
35546+
if ( globalUtilOptind >= argc )
35547+
{
35548+
Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer.\n" );
35549+
goto usage;
35550+
}
35551+
nOriginsMax = atoi(argv[globalUtilOptind]);
35552+
globalUtilOptind++;
35553+
if ( nOriginsMax < 0 )
35554+
{
35555+
Abc_Print( -1, "The max origins value should be non-negative.\n" );
35556+
goto usage;
35557+
}
35558+
fSetCap = 1;
35559+
break;
3554535560
case 'h':
3554635561
goto usage;
3554735562
default:
@@ -35553,6 +35568,12 @@ int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3555335568
Abc_Print( -1, "Abc_CommandAbc9Origins(): There is no AIG.\n" );
3555435569
return 0;
3555535570
}
35571+
if ( fSetCap )
35572+
{
35573+
pGia->nOriginsMax = nOriginsMax;
35574+
Abc_Print( 1, "Origins cap set to %d%s.\n", nOriginsMax, nOriginsMax ? "" : " (unlimited)" );
35575+
return 0;
35576+
}
3555635577
if ( pGia->vOrigins == NULL )
3555735578
{
3555835579
Abc_Print( 1, "No origin tracking data.\n" );
@@ -35594,8 +35615,9 @@ int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3559435615
return 0;
3559535616

3559635617
usage:
35597-
Abc_Print( -2, "usage: &origins [-h]\n" );
35618+
Abc_Print( -2, "usage: &origins [-M num] [-h]\n" );
3559835619
Abc_Print( -2, "\t prints multi-origin tracking statistics\n" );
35620+
Abc_Print( -2, "\t-M num : set max origins per object (0 = unlimited) [default = %d]\n", pGia ? pGia->nOriginsMax : 0 );
3559935621
Abc_Print( -2, "\t-h : print the command usage\n");
3560035622
return 1;
3560135623
}
@@ -35617,12 +35639,26 @@ int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3561735639
int Abc_CommandAbc9OriginsId( Abc_Frame_t * pAbc, int argc, char ** argv )
3561835640
{
3561935641
Gia_Man_t * pGia = pAbc->pGia;
35620-
int c;
35642+
int c, nOriginsMax = 0;
3562135643
Extra_UtilGetoptReset();
35622-
while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF )
35644+
while ( ( c = Extra_UtilGetopt( argc, argv, "Mh" ) ) != EOF )
3562335645
{
3562435646
switch ( c )
3562535647
{
35648+
case 'M':
35649+
if ( globalUtilOptind >= argc )
35650+
{
35651+
Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer.\n" );
35652+
goto usage;
35653+
}
35654+
nOriginsMax = atoi(argv[globalUtilOptind]);
35655+
globalUtilOptind++;
35656+
if ( nOriginsMax < 0 )
35657+
{
35658+
Abc_Print( -1, "The max origins value should be non-negative.\n" );
35659+
goto usage;
35660+
}
35661+
break;
3562635662
case 'h':
3562735663
goto usage;
3562835664
default:
@@ -35643,17 +35679,22 @@ int Abc_CommandAbc9OriginsId( Abc_Frame_t * pAbc, int argc, char ** argv )
3564335679
{
3564435680
int i, nObjs = Gia_ManObjNum(pGia);
3564535681
Gia_Obj_t * pObj;
35682+
pGia->nOriginsMax = nOriginsMax;
3564635683
pGia->vOrigins = Gia_ManOriginsAlloc( nObjs );
3564735684
Gia_ManForEachAnd( pGia, pObj, i )
3564835685
Gia_ObjSetOrigin( pGia, i, i );
35649-
Abc_Print( 1, "Initialized identity origins for %d AND nodes.\n", Gia_ManAndNum(pGia) );
35686+
Abc_Print( 1, "Initialized identity origins for %d AND nodes", Gia_ManAndNum(pGia) );
35687+
if ( nOriginsMax > 0 )
35688+
Abc_Print( 1, " (max %d per node)", nOriginsMax );
35689+
Abc_Print( 1, ".\n" );
3565035690
}
3565135691
return 0;
3565235692

3565335693
usage:
35654-
Abc_Print( -2, "usage: &origins_id [-h]\n" );
35694+
Abc_Print( -2, "usage: &origins_id [-M num] [-h]\n" );
3565535695
Abc_Print( -2, "\t sets identity origins for testing (each AND node -> itself)\n" );
3565635696
Abc_Print( -2, "\t in normal abc9 flow, origins come from XAIGER \"y\" extension\n" );
35697+
Abc_Print( -2, "\t-M num : max origins per object, 0 = unlimited [default = %d]\n", nOriginsMax );
3565735698
Abc_Print( -2, "\t-h : print the command usage\n");
3565835699
return 1;
3565935700
}

0 commit comments

Comments
 (0)