Fixed an error that was discovered with the drcCanonicalMaxwidth()

routine, which in turn affects various DRC rules like maxrect,
widespacing, and runlength spacing.  drcTile() was computing
the drcCanonicalMaxwidth() result for the tile and reusing it,
failing to account for the fact that within the loop over
DRCCookies, other rules might require calling drcCanonicalMaxwidth()
on a neighboring tile, or on the same tile with a different width
requirement.  Implemented a cached version, in which three results
are kept:  One for neighboring tiles (which can never be reused on
the same edge), one for the first required use of the routine for
the tile, and one for any other use required for the tile.  If
there are one or two such rules for an edge, then the routine will
work at maximum efficiency.  If there are three rules, then one
will always be a cache hit and reduce the total amount of
computation, although it will still be doing a massive amount of
redundant computation.  If this seems to be something that
occurs regularly, then it can be revisited.  The existing
implementation works fine for all the open PDKs.  Some more
advanced PDKs with a number of staged wide-spacing rules could
have issues.
This commit is contained in:
R. Timothy Edwards 2026-04-14 17:37:10 -04:00
parent 67c6ed9395
commit d157eea7f3
3 changed files with 57 additions and 9 deletions

View File

@ -1 +1 @@
8.3.636
8.3.637

View File

@ -524,6 +524,13 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
return (errors);
}
/* Expect that keeping around 3 MaxRectsData records should be sufficient
* to avoid recomputing drcCanonicalMaxwidth() multiple times. Note that
* if a PDK sets up multiple rules on an edge which all require running
* drcCanonicalMaxwidth(), then this cache size may need to be revisited.
*/
#define MAXRECTSCACHE 3
/*
* ----------------------------------------------------------------------------
*
@ -561,6 +568,19 @@ drcTile (tile, dinfo, arg)
int triggered;
int cdist, dist, ccdist, result;
/* Keep up to three MaxRectsData records to avoid doing the same
* expensive computation more than once.
*
* mrdcache[0] will be used for the tpleft tile, since it will never
* be reused. mrdcache[1] and mrdcache[2] will be used for the tile
* itself. Note that if more than 2 DRCCookie entries for the same
* edge require drcCanonicalMaxwidth(), then mrdcache[2] will be
* re-used so that at least mrdcache[1] is always a cache hit.
*/
static MaxRectsData *mrdcache[MAXRECTSCACHE] = {NULL, NULL, NULL};
DRCCookie *cptrcache;
arg->dCD_constraint = &errRect;
/*
@ -702,6 +722,8 @@ drcTile (tile, dinfo, arg)
DRCstatEdges++;
}
cptrcache = NULL;
/*
* Check design rules along a vertical boundary between two tiles.
*
@ -857,12 +879,23 @@ drcTile (tile, dinfo, arg)
if (cptr->drcc_flags & DRC_REVERSE)
{
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr);
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr,
&mrdcache[0]);
triggered = 0;
}
else if (firsttile)
else
{
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr);
if (cptrcache == NULL)
{
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
&mrdcache[1]);
cptrcache = cptr;
}
else if (cptrcache != cptr)
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
&mrdcache[2]);
else
mrd = mrdcache[1];
triggered = 0;
}
if (!trigpending || (DRCCurStyle->DRCFlags
@ -1153,6 +1186,8 @@ drcTile (tile, dinfo, arg)
}
}
cptrcache = NULL;
/*
* Check design rules along a horizontal boundary between two tiles.
*
@ -1299,12 +1334,23 @@ drcTile (tile, dinfo, arg)
if (cptr->drcc_flags & DRC_REVERSE)
{
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr);
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr,
&mrdcache[0]);
triggered = 0;
}
else if (firsttile)
else
{
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr);
if (cptrcache == NULL)
{
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
&mrdcache[1]);
cptrcache = cptr;
}
else if (cptrcache != cptr)
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
&mrdcache[2]);
else
mrd = mrdcache[1];
triggered = 0;
}
if (!trigpending || (DRCCurStyle->DRCFlags

View File

@ -510,16 +510,17 @@ MaxRectsExclude(
*/
MaxRectsData *
drcCanonicalMaxwidth(starttile, dir, arg, cptr)
drcCanonicalMaxwidth(starttile, dir, arg, cptr, mrdptr)
Tile *starttile;
int dir; /* direction of rule */
struct drcClientData *arg;
DRCCookie *cptr;
MaxRectsData **mrdptr;
{
int s, edgelimit;
Tile *tile,*tp;
TileTypeBitMask wrongtypes;
static MaxRectsData *mrd = (MaxRectsData *)NULL;
MaxRectsData *mrd = *mrdptr;
Rect *boundrect, boundorig;
/* Generate an initial array size of 8 for rlist and swap. */
@ -529,6 +530,7 @@ drcCanonicalMaxwidth(starttile, dir, arg, cptr)
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
mrd->listdepth = 8;
*mrdptr = mrd;
}
if (starttile == NULL) return mrd;