Skip to content

Commit 43bc82f

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 41b48b7 commit 43bc82f

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
@@ -221,6 +221,7 @@ struct Gia_Man_t_
221221
Vec_Int_t * vIdsEquiv; // original object IDs proved equivalent
222222
Vec_Int_t * vEquLitIds; // original object IDs proved equivalent
223223
Vec_Int_t * vOrigins; // per-object origin mapping (from "y" extension)
224+
int nOriginsMax; // max origins per object (0 = unlimited)
224225
Vec_Int_t * vCofVars; // cofactoring variables
225226
Vec_Vec_t * vClockDoms; // clock domains
226227
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
@@ -214,6 +214,9 @@ void Gia_ObjAddOrigin( Gia_Man_t * p, int iObj, int iOrig )
214214
e = Gia_ObjOriginsEntry( p, iObj );
215215
if ( Gia_ObjOriginsIsOverflow(e) )
216216
{
217+
// cap check: skip if at user-specified limit
218+
if ( p->nOriginsMax > 0 && e->large.count >= p->nOriginsMax )
219+
return;
217220
// overflow mode: check for duplicate
218221
for ( k = 0; k < e->large.count; k++ )
219222
if ( e->large.overflow[k] == iOrig ) return;
@@ -332,6 +335,7 @@ void Gia_ManOriginsDup( Gia_Man_t * pNew, Gia_Man_t * pOld )
332335
if ( !pOld->vOrigins )
333336
return;
334337
Gia_ManOriginsReset( pNew );
338+
pNew->nOriginsMax = pOld->nOriginsMax;
335339
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
336340
Gia_ManForEachObj( pOld, pObj, i )
337341
{
@@ -365,6 +369,7 @@ void Gia_ManOriginsDupVec( Gia_Man_t * pNew, Gia_Man_t * pOld, Vec_Int_t * vCopi
365369
if ( !pOld->vOrigins )
366370
return;
367371
Gia_ManOriginsReset( pNew );
372+
pNew->nOriginsMax = pOld->nOriginsMax;
368373
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
369374
Vec_IntForEachEntry( vCopies, iLit, i )
370375
{
@@ -400,6 +405,7 @@ void Gia_ManOriginsAfterRoundTrip( Gia_Man_t * pNew, Gia_Man_t * pOld )
400405
assert( Gia_ManCiNum(pNew) == Gia_ManCiNum(pOld) );
401406
assert( Gia_ManCoNum(pNew) == Gia_ManCoNum(pOld) );
402407
Gia_ManOriginsReset( pNew );
408+
pNew->nOriginsMax = pOld->nOriginsMax;
403409
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
404410
// const0
405411
Gia_ObjUnionOrigins( pNew, 0, pOld, 0 );
@@ -457,6 +463,7 @@ void Gia_ManOriginsDupIf( Gia_Man_t * pNew, Gia_Man_t * p, void * pIfManVoid )
457463
if ( !p->vOrigins )
458464
return;
459465
Gia_ManOriginsReset( pNew );
466+
pNew->nOriginsMax = p->nOriginsMax;
460467
pNew->vOrigins = Gia_ManOriginsAlloc( Gia_ManObjNum(pNew) );
461468
If_ManForEachObj( pIfMan, pIfObj, i )
462469
{
@@ -1109,6 +1116,7 @@ Gia_Man_t * Gia_ManDupWithAttributes( Gia_Man_t * p )
11091116
if ( p->pCellStr )
11101117
pNew->pCellStr = Abc_UtilStrsav( p->pCellStr );
11111118
// copy origins if present (deep-copy overflow arrays)
1119+
pNew->nOriginsMax = p->nOriginsMax;
11121120
if ( p->vOrigins )
11131121
{
11141122
int iObj, nObjs;

src/base/abci/abc.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35561,12 +35561,27 @@ int Abc_CommandAbc9Ps( Abc_Frame_t * pAbc, int argc, char ** argv )
3556135561
int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3556235562
{
3556335563
Gia_Man_t * pGia = pAbc->pGia;
35564-
int c;
35564+
int c, fSetCap = 0, nOriginsMax = 0;
3556535565
Extra_UtilGetoptReset();
35566-
while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF )
35566+
while ( ( c = Extra_UtilGetopt( argc, argv, "Mh" ) ) != EOF )
3556735567
{
3556835568
switch ( c )
3556935569
{
35570+
case 'M':
35571+
if ( globalUtilOptind >= argc )
35572+
{
35573+
Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer.\n" );
35574+
goto usage;
35575+
}
35576+
nOriginsMax = atoi(argv[globalUtilOptind]);
35577+
globalUtilOptind++;
35578+
if ( nOriginsMax < 0 )
35579+
{
35580+
Abc_Print( -1, "The max origins value should be non-negative.\n" );
35581+
goto usage;
35582+
}
35583+
fSetCap = 1;
35584+
break;
3557035585
case 'h':
3557135586
goto usage;
3557235587
default:
@@ -35578,6 +35593,12 @@ int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3557835593
Abc_Print( -1, "Abc_CommandAbc9Origins(): There is no AIG.\n" );
3557935594
return 0;
3558035595
}
35596+
if ( fSetCap )
35597+
{
35598+
pGia->nOriginsMax = nOriginsMax;
35599+
Abc_Print( 1, "Origins cap set to %d%s.\n", nOriginsMax, nOriginsMax ? "" : " (unlimited)" );
35600+
return 0;
35601+
}
3558135602
if ( pGia->vOrigins == NULL )
3558235603
{
3558335604
Abc_Print( 1, "No origin tracking data.\n" );
@@ -35619,8 +35640,9 @@ int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3561935640
return 0;
3562035641

3562135642
usage:
35622-
Abc_Print( -2, "usage: &origins [-h]\n" );
35643+
Abc_Print( -2, "usage: &origins [-M num] [-h]\n" );
3562335644
Abc_Print( -2, "\t prints multi-origin tracking statistics\n" );
35645+
Abc_Print( -2, "\t-M num : set max origins per object (0 = unlimited) [default = %d]\n", pGia ? pGia->nOriginsMax : 0 );
3562435646
Abc_Print( -2, "\t-h : print the command usage\n");
3562535647
return 1;
3562635648
}
@@ -35642,12 +35664,26 @@ int Abc_CommandAbc9Origins( Abc_Frame_t * pAbc, int argc, char ** argv )
3564235664
int Abc_CommandAbc9OriginsId( Abc_Frame_t * pAbc, int argc, char ** argv )
3564335665
{
3564435666
Gia_Man_t * pGia = pAbc->pGia;
35645-
int c;
35667+
int c, nOriginsMax = 0;
3564635668
Extra_UtilGetoptReset();
35647-
while ( ( c = Extra_UtilGetopt( argc, argv, "h" ) ) != EOF )
35669+
while ( ( c = Extra_UtilGetopt( argc, argv, "Mh" ) ) != EOF )
3564835670
{
3564935671
switch ( c )
3565035672
{
35673+
case 'M':
35674+
if ( globalUtilOptind >= argc )
35675+
{
35676+
Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer.\n" );
35677+
goto usage;
35678+
}
35679+
nOriginsMax = atoi(argv[globalUtilOptind]);
35680+
globalUtilOptind++;
35681+
if ( nOriginsMax < 0 )
35682+
{
35683+
Abc_Print( -1, "The max origins value should be non-negative.\n" );
35684+
goto usage;
35685+
}
35686+
break;
3565135687
case 'h':
3565235688
goto usage;
3565335689
default:
@@ -35668,17 +35704,22 @@ int Abc_CommandAbc9OriginsId( Abc_Frame_t * pAbc, int argc, char ** argv )
3566835704
{
3566935705
int i, nObjs = Gia_ManObjNum(pGia);
3567035706
Gia_Obj_t * pObj;
35707+
pGia->nOriginsMax = nOriginsMax;
3567135708
pGia->vOrigins = Gia_ManOriginsAlloc( nObjs );
3567235709
Gia_ManForEachAnd( pGia, pObj, i )
3567335710
Gia_ObjSetOrigin( pGia, i, i );
35674-
Abc_Print( 1, "Initialized identity origins for %d AND nodes.\n", Gia_ManAndNum(pGia) );
35711+
Abc_Print( 1, "Initialized identity origins for %d AND nodes", Gia_ManAndNum(pGia) );
35712+
if ( nOriginsMax > 0 )
35713+
Abc_Print( 1, " (max %d per node)", nOriginsMax );
35714+
Abc_Print( 1, ".\n" );
3567535715
}
3567635716
return 0;
3567735717

3567835718
usage:
35679-
Abc_Print( -2, "usage: &origins_id [-h]\n" );
35719+
Abc_Print( -2, "usage: &origins_id [-M num] [-h]\n" );
3568035720
Abc_Print( -2, "\t sets identity origins for testing (each AND node -> itself)\n" );
3568135721
Abc_Print( -2, "\t in normal abc9 flow, origins come from XAIGER \"y\" extension\n" );
35722+
Abc_Print( -2, "\t-M num : max origins per object, 0 = unlimited [default = %d]\n", nOriginsMax );
3568235723
Abc_Print( -2, "\t-h : print the command usage\n");
3568335724
return 1;
3568435725
}

0 commit comments

Comments
 (0)