LichenCleanup.Mesa
Last tweaked by Mike Spreitzer on April 14, 1989 9:34:52 am PDT
DIRECTORY AbSets, BiRels, IntStuff, IO, LichenDataOps, LichenDataStructure, LichenIntBasics, Rope, SetBasics;
LichenCleanup: CEDAR PROGRAM
IMPORTS AbSets, BiRels, IntStuff, IO, LichenDataOps, LichenDataStructure, SetBasics
EXPORTS LichenDataOps
=
BEGIN OPEN IS:IntStuff, LIB:LichenIntBasics, LIB, LichenDataStructure, LichenDataOps, Sets:AbSets;
ropeSets: Sets.Space ~ Sets.CreateSetSpace[SetBasics.ropes[TRUE]];
steppySets: Sets.Space ~ Sets.CreateSetSpace[steppyNameSpace];
CleanDesign: PUBLIC PROC [d: Design, pacify: IO.STREAMNIL] RETURNS [losses: ARRAY EClass OF Set--of set of name--] ~ {
doneUp: Set--of CellTye-- ~ Sets.CreateHashSet[d.eSpace];
doneDown: Set--of CellTye-- ~ Sets.CreateHashSet[d.eSpace];
CleanUp1: PROC [ctv: Sets.Value] RETURNS [BOOL] ~ {
IF NOT doneUp.AddElt[ctv] THEN RETURN [FALSE];
{ct: CellType ~ NARROW[ctv.VA];
views: NAT ~ (IF ct.asu#NIL THEN 1 ELSE 0) + (IF ct.asArray#NIL THEN 1 ELSE 0) + (IF ct.asTrans#NIL THEN 1 ELSE 0);
wires: Set ~ ct.CTParts[w];
cis: Set ~ ct.Subcells[];
insts: Set ~ ct.CtInsts[];
arrays: Set ~ ct.CtArrays[];
unused: BOOL ~ insts.Empty AND arrays.Empty;
CheckWire: PROC [wv: Sets.Value] RETURNS [BOOL] ~ {
IF ct.asu.exports.MappingSize[wv, rightToLeft, IS.two].EN > 1 THEN ERROR;
RETURN [FALSE]};
IF views>1 THEN ERROR;
IF wires.Scan[CheckWire].found THEN ERROR;
IF ct#d.root AND unused THEN {
IF pacify#NIL THEN pacify.PutF["DelCT %g unused.\n", [rope[ct.ACtName]]];
DeleteCellType[ct, FALSE, pacify]; RETURN [FALSE]};
{calledTypes: Set ~ IF ct.asu#NIL THEN d.ciType.Image[cis] ELSE IF ct.asArray#NIL THEN d.arrayElt.Mapping[ctv] ELSE emptyRopeSet;
IF calledTypes.Scan[CleanUp1].found THEN ERROR;
IF ct.asu#NIL AND cis.Empty THEN {
IF pacify#NIL THEN pacify.PutF["DelCT %g empty.\n", [rope[ct.ACtName]]];
DeleteCellType[ct, FALSE, pacify]; RETURN [FALSE]};
IF ct.asu#NIL THEN {
calledTypes: Set ~ d.ciType.Image[cis];
topPorts: Set ~ ct.TopParts[p];
CheckWire: PROC [wv: Sets.Value] RETURNS [BOOL] ~ {
IF ct.asu.exports.MappingSize[wv, rightToLeft, IS.two].EN > 1 THEN ERROR;
RETURN [FALSE]};
TryPortTree1: PROC [pv: Sets.Value] RETURNS [BOOL] ~ {
IF NOT topPorts.HasMember[pv] THEN RETURN [FALSE];
{root: Port ~ NARROW[pv.VA];
tree: Set ~ d.PWDescendants[root].CreateHashCopy[];
exws: Set ~ ct.asu.exports.Image[tree] .Intersection[d.wiresConnectedAtSomeInstance];
IF exws.Empty THEN {
whyNot: ROPE ~ MayDeletePorts[ct, tree, TRUE, TRUE];
IF whyNot#NIL THEN {
IF pacify#NIL THEN pacify.PutF["Not DelPT %g 'cause %g.\n", [rope[Describe[d, root, d]]], [rope[whyNot]]];
}
ELSE {
naming: BiRel ~ ct.fullName[p].Intersection[BiRels.CreateProduct[[tree, Sets.CreateFullSet[steppyNameSpace]]]].GenCopy[mappable: ALL[TRUE], hints: pwNameHints];
nameses: Set ~ naming.Collect[].SetOn[right];
IF pacify#NIL THEN pacify.PutF["DelPT %g nocon.\n", [rope[Describe[d, root, d]]]];
[] ← losses[p].AddSet[nameses];
DeletePorts[ct, tree, TRUE, FALSE, pacify]}};
RETURN [FALSE]}};
IF wires.Scan[CheckWire].found THEN ERROR;
IF topPorts.Scan[TryPortTree1].found THEN ERROR;
IF wires.Scan[TryWire].found THEN ERROR;
}
ELSE IF ct.asArray#NIL THEN {
et: CellType ~ EltType[ct];
IF CleanUp1[AV[et]] THEN ERROR};
RETURN [FALSE]}}};
TryWire: PROC [wv: Sets.Value] RETURNS [BOOL] ~ {
w: Wire ~ NARROW[wv.VA];
IF w.conns.Empty THEN {
ct: CellType ~ d.WCct[w];
IF pacify#NIL THEN pacify.PutF["DelW %g nocon.\n", [rope[Describe[d, w, d]]]];
[] ← losses[w].AddElt[ct.WNames[w].CreateRedBlackCopy[].SV];
DeleteWires[ct, Sets.CreateSingleA[w, d.eSpace], FALSE]};
RETURN [FALSE]};
CleanDown: PROC [ctv: Sets.Value] RETURNS [BOOL] ~ {
IF NOT doneDown.AddElt[ctv] THEN RETURN [FALSE];
{ct: CellType ~ NARROW[ctv.VA];
insts: Set ~ ct.CtInsts[];
callingTypes: Set ~ d.cct[i].Image[insts].Union[ct.CtArrays[]];
topPorts: Set ~ ct.TopParts[p];
TryPortTree2: PROC [pv: Sets.Value] RETURNS [BOOL] ~ {
IF NOT topPorts.HasMember[pv] THEN RETURN [FALSE];
{root: Port ~ NARROW[pv.VA];
tree: Set ~ d.PWDescendants[root].CreateHashCopy[];
nontrivial: BOOLFALSE;
CheckUse: PROC [cu: CellUse] ~ {
IF nontrivial THEN RETURN;
WITH cu SELECT FROM
act: CellType => {
sr: StatRep ~ act.asArray.statrep;
dr: DumRep ~ act.asArray.dumrep;
IF sr.portEdge[FALSE].Image[tree].Empty AND sr.portEdge[TRUE].Image[tree].Empty AND dr.apToWire.Image[dr.epw.Image[tree], rightToLeft].Empty THEN d ← d ELSE nontrivial ← TRUE};
ci: CellInstance => {
interesting: Set ~ ci.conns.Image[tree].Intersection[d.nontriviallyConnectedWires];
IF interesting.Empty THEN d ← d ELSE nontrivial ← TRUE};
ENDCASE => ERROR;
RETURN};
ct.EnumerateUses[CheckUse];
IF NOT nontrivial THEN {
naming: BiRel ~ ct.fullName[p].Intersection[BiRels.CreateProduct[[tree, Sets.CreateFullSet[steppyNameSpace]]]].GenCopy[mappable: ALL[TRUE], hints: pwNameHints];
nameses: Set ~ naming.Collect[].SetOn[right];
IF pacify#NIL THEN pacify.PutF["DelPT %g bu.\n", [rope[Describe[d, root, d]]]];
[] ← losses[p].AddSet[nameses];
DeletePorts[ct, tree, TRUE, TRUE, pacify]};
RETURN [FALSE]}};
IF ct=d.root THEN {
IF NOT callingTypes.Empty THEN ERROR;
RETURN [FALSE]};
IF callingTypes.Scan[CleanDown].found THEN ERROR;
IF topPorts.Scan[TryPortTree2].found THEN ERROR;
RETURN [FALSE]}};
CleanUp2: PROC [ctv: Sets.Value] RETURNS [BOOL] ~ {
IF NOT doneUp.AddElt[ctv] THEN RETURN [FALSE];
IF NOT d.cellTypes.HasMember[ctv] THEN RETURN [FALSE];
{ct: CellType ~ NARROW[ctv.VA];
ports: Set ~ ct.CTParts[p];
wires: Set ~ ct.CTParts[w];
cis: Set ~ ct.Subcells[];
insts: Set ~ ct.CtInsts[];
arrays: Set ~ ct.CtArrays[];
noports, unused: BOOL;
IF ct.asu#NIL THEN {
calledTypes: Set ~ d.ciType.Image[cis];
IF calledTypes.Scan[CleanUp2].found THEN ERROR;
IF wires.Scan[TryWire].found THEN ERROR;
IF ct=d.root THEN noports ← FALSE
ELSE {
noSubcells: BOOL ~ cis.Empty;
noports ← ports.Empty;
IF noSubcells AND NOT noports THEN ERROR;
};
}
ELSE IF ct.asArray#NIL THEN {
et: CellType ~ EltType[ct];
IF CleanUp2[AV[et]] THEN ERROR;
IF NOT d.cellTypes.HasMemA[et] THEN {
IF d.cellTypes.HasMember[ctv] THEN ERROR;
IF ct=d.root THEN ERROR;
RETURN [FALSE]};
noports ← ports.Empty}
ELSE noports ← ports.Empty;
unused ← insts.Empty AND arrays.Empty;
IF ct#d.root AND (noports OR unused) THEN {
cis: Set ~ ct.Subcells[];
wires: Set ~ ct.CTParts[w];
subcells: Set ~ ct.Subcells;
IF pacify#NIL THEN pacify.PutF["DelCT %g np:%g, uu:%g.\n", [rope[ct.ACtName]], [boolean[noports]], [boolean[unused]]];
[] ← losses[t].AddElt[d.CTNames[ct].CreateHashCopy.SV];
DeleteCellType[ct, FALSE, pacify];
};
RETURN [FALSE]}};
losses[t] ← Sets.CreateHashSet[ropeSets];
FOR ec: EClass IN [p .. t) DO losses[ec] ← Sets.CreateHashSet[steppySets] ENDLOOP;
IF pacify#NIL THEN pacify.PutRope["Pass 1.\n"];
[] ← CleanUp1[AV[d.root]];
IF pacify#NIL THEN pacify.PutRope["Pass 2.\n"];
IF d.cellTypes.Scan[CleanDown].found THEN ERROR;
doneUp.Erase[];
IF pacify#NIL THEN pacify.PutRope["Pass 3.\n"];
IF d.cellTypes.Scan[CleanUp2].found THEN ERROR;
RETURN};
DeleteCellTypes: PUBLIC PROC [cts: Set, recurse: BOOL, log: IO.STREAMNIL] ~ {
PerCT: PROC [ctv: Sets.Value] RETURNS [BOOL] ~ {
ct: CellType ~ NARROW[ctv.VA];
DeleteCellType[ct, recurse, log];
RETURN [FALSE]};
IF cts.Scan[PerCT].found THEN ERROR;
RETURN};
DeleteCellType: PUBLIC PROC [ct: CellType, recurse: BOOL, log: IO.STREAMNIL] ~ {
d: Design ~ ct.d;
oldInsts: Set ~ ct.CtInsts[].CreateHashCopy[];
DeleteArrayOfSelf: PROC [actv: Sets.Value] RETURNS [BOOL] ~ {
act: CellType ~ NARROW[actv.VA];
IF log#NIL THEN log.PutF["DelArray[%g, elt gone]\n", [rope[act.ACtName]]];
DeleteCellType[act, FALSE, log];
RETURN [FALSE]};
IF ct.CtArrays[].CreateHashCopy[].Scan[DeleteArrayOfSelf].found THEN ERROR;
IF NOT oldInsts.Empty THEN DeleteInsts[d, oldInsts, TRUE, FALSE];
IF ct.asu#NIL THEN {
DeleteInsts[d, ct.Subcells[].CreateHashCopy[], FALSE, recurse, log];
DeleteWires[ct, ct.CTParts[w].CreateHashCopy[], FALSE];
ct ← ct};
IF ct.asArray#NIL THEN {
ect: CellType ~ ct.EltType[];
IF ect=NIL THEN ERROR;
[] ← d.arrayElt.DeleteA[ct];
IF recurse AND d.cellTypes.HasMemA[ect] AND ect.Unused[] THEN {
IF log#NIL THEN log.PutF["Deleting %g 'cause last use (an array) was deleted.\n", [rope[d.Describe[ect, d]]]];
DeleteCellType[ect, recurse, log];
recurse ← recurse};
ct ← ct};
DeletePorts[ct, ct.CTParts[p].CreateHashCopy[], FALSE, FALSE, log];
IF NOT d.cellTypes.RemA[ct] THEN ERROR;
FOR pc: PartClass IN PartClass DO IF NOT d.cct[pc].MappingEmpty[AV[ct], rightToLeft] THEN ERROR ENDLOOP;
IF NOT d.ciType.MappingEmpty[AV[ct], rightToLeft] THEN ERROR;
[] ← d.ctName.DeleteA[ct];
[] ← d.labelCellTypes.RemA[ct];
[] ← d.crossedCellTypes.RemA[ct];
ct^ ← [];
RETURN};
DeleteInsts: PUBLIC PROC [d: Design, cis: Set, visitWires, killCTs: BOOL, log: IO.STREAMNIL] ~ {
suspectCTs: Set ~ IF killCTs THEN d.ciType.Image[cis].CreateHashCopy[] ELSE nilSet;
NilCI: PROC [civ: Sets.Value] RETURNS [BOOL] ~ {
FixWire: PROC [wv: Sets.Value] RETURNS [BOOL] ~ {
w: Wire ~ NARROW[wv.VA];
[] ← w.conns.Delete[civ, right];
RETURN [FALSE]};
ci: CellInstance ~ NARROW[civ.VA];
cct: CellType ~ d.CiCct[ci];
IF visitWires THEN IF ci.conns.SetOn[right].Scan[FixWire].found THEN ERROR;
[] ← cct.fullName[i].Delete[civ];
ci.conns ← nilBiRel;
RETURN [FALSE]};
IF cis.Empty THEN RETURN;
IF cis.Scan[NilCI].found THEN ERROR;
[] ← d.ciType.DeleteSet[cis];
IF d.physd THEN [] ← d.ciXfm.DeleteSet[cis];
[] ← d.cct[i].DeleteSet[cis];
IF killCTs THEN {
KillIfUnused: PROC [ctv: Sets.Value] RETURNS [BOOL] ~ {
ct: CellType ~ NARROW[ctv.VA];
IF d.cellTypes.HasMemA[ct] AND ct.Unused[] THEN {
IF log#NIL THEN log.PutF["Deleting %g 'cause last use (an instance) was deleted.\n", [rope[d.Describe[ct, d]]]];
DeleteCellType[ct, TRUE, log];
d ← d};
RETURN [FALSE]};
IF suspectCTs.Scan[KillIfUnused].found THEN ERROR};
RETURN};
END.