-- Flow.mesa last modified by Sweet, January 16, 1980 9:05 AM DIRECTORY AltoDefs: FROM "altodefs" USING [BYTE, charlength, wordlength], Code: FROM "code" USING [ caseCVState, catchcount, CodeNotImplemented, curctxlvl, dStar], CodeDefs: FROM "codedefs" USING [ EXLabelRecord, EXLRIndex, EXLRNull, JumpType, LabelCCIndex, Lexeme, NullLex, VarComponent, VarIndex], ControlDefs: FROM "controldefs" USING [localbase, returnOffset], FOpCodes: FROM "fopcodes" USING [ qDCOMP, qDUCOMP, qFCOMP, qLI, qLL, qLP, qOR, qPUSH, qSFC], P5: FROM "p5" USING [ Exp, FreeHeapLex, GenAnonLex, LogHeapFree, PushLex, PushRhs, StatementTree, SysCall], P5L: FROM "p5l" USING [ EasilyLoadable, FieldOfVar, InCode, LoadAddress, LoadBoth, LoadComponent, LongVarAddress, MakeComponent, ReusableCopies, VarAlignment, VarForLex, Words], P5S: FROM "p5s", P5U: FROM "p5u" USING [ FreeChunk, GetChunk, InsertLabel, LabelAlloc, Out0, Out1, OutJump, PushLitVal, TreeLiteral, TreeLiteralValue], SDDefs: FROM "sddefs" USING [sBLTE, sBLTEC, sBLTECL, sBLTEL], Stack: FROM "stack" USING [Decr, Dump, Incr, Mark, Require], Symbols: FROM "symbols" USING [ ContextLevel, CTXIndex, HTIndex, HTNull, ISEIndex, SEIndex, seType], Table: FROM "table" USING [Base, Limit, Notifier], Tree: FROM "tree" USING [Index, Link, NodeName, Null, treeType], TreeOps: FROM "treeops" USING [ScanList]; Flow: PROGRAM IMPORTS CPtr: Code, P5U, CodeDefs, P5L, P5, TreeOps, Stack EXPORTS CodeDefs, P5, P5S = BEGIN OPEN CodeDefs; -- imported definitions BYTE: TYPE = AltoDefs.BYTE; wordlength: CARDINAL = AltoDefs.wordlength; charlength: CARDINAL = AltoDefs.charlength; ContextLevel: TYPE = Symbols.ContextLevel; CTXIndex: TYPE = Symbols.CTXIndex; HTIndex: TYPE = Symbols.HTIndex; HTNull: HTIndex = Symbols.HTNull; ISEIndex: TYPE = Symbols.ISEIndex; SEIndex: TYPE = Symbols.SEIndex; CRLabelRecord: TYPE = RECORD [ free: BOOLEAN, retrylabel, contlabel: LabelCCIndex, crcc: CARDINAL]; CRLRIndex: TYPE = Table.Base RELATIVE POINTER [0..Table.Limit) TO CRLabelRecord; CRLRNull: CRLRIndex = LOOPHOLE[Table.Limit-1]; labelStack: EXLRIndex ← EXLRNull; CRlabel: CRLRIndex ← CRLRNull; UndeclaredLabel: SIGNAL[HTIndex] = CODE; tb: Table.Base; -- tree base (local copy) seb: Table.Base; -- semantic entry base (local copy) cb: Table.Base; -- code base (local copy) FlowNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked seb ← base[Symbols.seType]; cb ← tb ← base[Tree.treeType]; RETURN END; JumpNN: PACKED ARRAY Tree.NodeName[relE..relLE] OF JumpType ← [ JumpE, JumpN, JumpL, JumpGE, JumpG, JumpLE]; UJumpNN: PACKED ARRAY Tree.NodeName[relE..relLE] OF JumpType ← [ JumpE, JumpN, UJumpL, UJumpGE, UJumpG, UJumpLE]; RNN: ARRAY Tree.NodeName[relE..relLE] OF Tree.NodeName = [ relE, relN, relG, relLE, relL, relGE]; CNN: ARRAY Tree.NodeName[relE..relLE] OF Tree.NodeName = [ relN, relE, relGE, relL, relLE, relG]; FlowTree: PUBLIC PROCEDURE [t: Tree.Link, tf: BOOLEAN, label: LabelCCIndex] = BEGIN -- produces code to jump to label on condition tf node: Tree.Index; label1: LabelCCIndex; sw: BOOLEAN; WITH t SELECT FROM symbol => BEGIN l: se Lexeme; IF ~CPtr.dStar THEN Stack.Dump[]; l ← [se[index]]; P5.PushLex[l]; P5U.PushLitVal[0]; P5U.OutJump[IF tf THEN JumpN ELSE JumpE, label]; RETURN END; subtree => BEGIN node ← index; SELECT tb[node].name FROM and, or => BEGIN ENABLE P5.LogHeapFree => RESUME[FALSE, NullLex]; sw ← IF tb[node].name = and THEN tf ELSE ~tf; IF sw THEN BEGIN label1←P5U.LabelAlloc[]; FlowTree[tb[node].son[1], ~tf, label1]; FlowTree[tb[node].son[2], tf, label]; P5U.InsertLabel[label1]; END ELSE BEGIN FlowTree[tb[node].son[1], tf, label]; FlowTree[tb[node].son[2], tf, label]; END; END; not => FlowTree[tb[node].son[1], ~tf, label]; in => FlowIn[t, tf, label]; notin => FlowIn[t, ~tf, label]; relE, relN, relL, relGE, relG, relLE => SFRel[node, tf, label]; ENDCASE => -- must be a BOOLEAN expression BEGIN IF ~CPtr.dStar THEN IF t = Tree.Null AND CPtr.caseCVState = singleLoaded THEN Stack.Require[1] ELSE Stack.Dump[]; P5.PushRhs[t]; P5U.PushLitVal[0]; P5U.OutJump[IF tf THEN JumpN ELSE JumpE, label]; END; END; literal => BEGIN val: CARDINAL ← P5U.TreeLiteralValue[t]; IF tf = (val # 0) THEN P5U.OutJump[Jump, label]; END; ENDCASE; RETURN END; SFRel: PROCEDURE [node: Tree.Index, tf: BOOLEAN, label: LabelCCIndex] = BEGIN -- main subroutine of Cflow for handling relationals t1: Tree.Link ← tb[node].son[1]; t2: Tree.Link; n: Tree.NodeName ← tb[node].name; hLex1, hLex2: se Lexeme ← NullLex; r1, r2: VarIndex; IF ~CPtr.dStar THEN IF t1 = Tree.Null AND CPtr.caseCVState = singleLoaded THEN Stack.Require[1] ELSE Stack.Dump[]; IF P5U.TreeLiteral[t1] THEN BEGIN n ← RNN[n]; t2 ← t1; t1 ← tb[node].son[2]; END ELSE t2 ← tb[node].son[2]; IF ~tf THEN n ← CNN[n]; r1 ← P5L.VarForLex[P5.Exp[t1!P5.LogHeapFree => IF calltree = t1 THEN RESUME[TRUE, hLex1 ← P5.GenAnonLex[1]]]]; r2 ← P5L.VarForLex[P5.Exp[t2!P5.LogHeapFree => IF calltree = t2 THEN RESUME[TRUE, hLex2 ← P5.GenAnonLex[1]]]]; VarVarComp[ r1: r1, r2: r2, n: n, real: tb[node].attr1, signed: tb[node].attr3, hLex1: hLex1, hLex2: hLex2, label: label]; END; VarVarComp: PUBLIC PROCEDURE [r1, r2: VarIndex, n: Tree.NodeName, real, signed: BOOLEAN, hLex1, hLex2: se Lexeme, label: LabelCCIndex] = BEGIN -- if ~dStar, stack should be "empty" when called wSize: CARDINAL; bSize, bd1, bd2: [0..wordlength); ws: CARDINAL; FreeHeapNodes: PROCEDURE = BEGIN IF hLex1 # NullLex THEN P5.FreeHeapLex[hLex1]; IF hLex2 # NullLex THEN P5.FreeHeapLex[hLex2]; hLex1 ← hLex2 ← NullLex; END; [wSize: wSize, bSize: bSize, bd: bd1] ← P5L.VarAlignment[r1, load]; [bd: bd2] ← P5L.VarAlignment[r2, load]; ws ← P5L.Words[wSize, bSize]; -- r1 and r2 are same size if > 1 IF ws > 1 AND bd1 # bd2 THEN SIGNAL CPtr.CodeNotImplemented; IF ws <= 2 THEN BEGIN c1: VarComponent ← P5L.MakeComponent[r1]; c2: VarComponent ← P5L.MakeComponent[r2]; BEGIN IF n = relE OR n = relN THEN WITH c2 SELECT FROM const => IF wSize = 2 AND bSize = 0 AND d1 = 0 AND d2 = 0 THEN BEGIN P5L.LoadComponent[c1]; P5U.Out0[FOpCodes.qOR]; GO TO double; END; ENDCASE; P5L.LoadBoth[@c1, @c2, FALSE]; IF ws = 2 THEN BEGIN P5U.Out0[IF real THEN FOpCodes.qFCOMP ELSE IF signed THEN FOpCodes.qDCOMP ELSE FOpCodes.qDUCOMP]; GO TO double; END; FreeHeapNodes[]; EXITS double => BEGIN FreeHeapNodes[]; P5U.Out1[FOpCodes.qLI, 0] END; END; P5U.OutJump[IF signed OR ws = 2 THEN JumpNN[n] ELSE UJumpNN[n], label]; END ELSE BEGIN -- multiword quantities, n = relE or relN IF bSize = 0 THEN BEGIN code: BOOLEAN ← FALSE; long1, long2: BOOLEAN; CompFn: ARRAY BOOLEAN OF ARRAY BOOLEAN OF BYTE = [ [SDDefs.sBLTE, SDDefs.sBLTEL], [SDDefs.sBLTEC, SDDefs.sBLTECL]]; Stack.Dump[]; Stack.Mark[]; -- so procedure call will work IF P5L.InCode[r1] THEN BEGIN tr: VarIndex = r1; r1 ← r2; r2 ← tr END; IF P5L.InCode[r2] THEN code ← TRUE; long2 ← P5L.LongVarAddress[r2]; long1 ← P5L.LoadAddress[r: r1, codeOk: FALSE]; IF ~long1 AND long2 THEN BEGIN P5U.Out0[FOpCodes.qLP]; long1 ← TRUE END; P5U.Out1[FOpCodes.qLI, ws]; [] ← P5L.LoadAddress[r: r2, codeOk: TRUE]; IF ~code AND long1 AND ~long2 THEN P5U.Out0[FOpCodes.qLP]; P5.SysCall[CompFn[code][long1]]; Stack.Incr[1]; FreeHeapNodes[]; P5U.Out1[FOpCodes.qLI, 0]; P5U.OutJump[IF n # relE THEN JumpE ELSE JumpN, label] END ELSE BEGIN -- do in two pieces r1a, r1b: VarIndex; r2a, r2b: VarIndex; firstEq, secondComp: LabelCCIndex; [r1a, r1b] ← P5L.ReusableCopies[r1, load]; [r2a, r2b] ← P5L.ReusableCopies[r2, load]; IF bd1 # 0 THEN BEGIN P5L.FieldOfVar[r: r1b, bSize: bSize]; P5L.FieldOfVar[r: r1a, bd: bSize, wSize: wSize]; P5L.FieldOfVar[r: r2b, bSize: bSize]; P5L.FieldOfVar[r: r2a, bd: bSize, wSize: wSize]; END ELSE BEGIN P5L.FieldOfVar[r: r1b, wSize: wSize]; P5L.FieldOfVar[r: r1a, wd: wSize, bSize: bSize]; P5L.FieldOfVar[r: r2b, wSize: wSize]; P5L.FieldOfVar[r: r2a, wd: wSize, bSize: bSize]; END; secondComp ← P5U.LabelAlloc[]; IF n = relN THEN firstEq ← label ELSE firstEq ← P5U.LabelAlloc[]; VarVarComp[ r1b, r2b, relE, real, signed, NullLex, NullLex, secondComp]; FreeHeapNodes[]; -- this looks awful here, but Final sorts it all out P5U.OutJump[Jump, firstEq]; P5U.InsertLabel[secondComp]; VarVarComp[r1a, r2a, n, real, signed, hLex1, hLex2, label]; IF n # relN THEN P5U.InsertLabel[firstEq]; END; END; END; FlowIn: PUBLIC PROCEDURE [t: Tree.Link, tf: BOOLEAN, label: LabelCCIndex] = BEGIN -- generates code for IN expression in flow context node: Tree.Index; n: Tree.NodeName; fail: LabelCCIndex ← P5U.LabelAlloc[]; jumpNN: POINTER TO PACKED ARRAY Tree.NodeName[relE..relLE] OF JumpType; double, real: BOOLEAN; signed: BOOLEAN; r1: VarIndex; var1: VarComponent; t1: Tree.Link; hLex: se Lexeme ← NullLex; WITH t SELECT FROM subtree => BEGIN node ← index; t1 ← tb[node].son[1]; WITH tb[node].son[2] SELECT FROM -- the interval node subtree => BEGIN inn: Tree.Index ← index; real ← tb[inn].attr1; double ← real OR tb[inn].attr2; signed ← tb[inn].attr3; END; ENDCASE => ERROR; IF real OR ~CPtr.dStar THEN IF t = Tree.Null AND CPtr.caseCVState = singleLoaded THEN Stack.Require[1] ELSE Stack.Dump[]; r1 ← P5L.VarForLex[P5.Exp[t1 ! P5.LogHeapFree => IF calltree = t1 THEN RESUME[TRUE, hLex ← P5.GenAnonLex[1]]]]; var1 ← P5L.MakeComponent[r1]; IF double THEN var1 ← P5L.EasilyLoadable[var1, load]; P5L.LoadComponent[var1]; IF hLex # NullLex THEN BEGIN P5.FreeHeapLex[hLex]; hLex ← NullLex END; WITH tb[node].son[2] SELECT FROM subtree => BEGIN node ← index; jumpNN ← IF double OR signed THEN @JumpNN ELSE @UJumpNN; n ← tb[node].name; P5.PushRhs[tb[node].son[1] ! P5.LogHeapFree => IF calltree = t1 THEN RESUME[TRUE, hLex ← P5.GenAnonLex[1]]]; IF double THEN BEGIN P5U.Out0[IF real THEN FOpCodes.qFCOMP ELSE IF signed THEN FOpCodes.qDCOMP ELSE FOpCodes.qDUCOMP]; P5U.PushLitVal[0]; END; IF hLex # NullLex THEN BEGIN P5.FreeHeapLex[hLex]; hLex ← NullLex END; SELECT n FROM intOO,intOC => P5U.OutJump[jumpNN[relLE], IF tf THEN fail ELSE label]; intCO,intCC => P5U.OutJump[jumpNN[relL], IF tf THEN fail ELSE label]; ENDCASE; IF double THEN P5L.LoadComponent[var1] ELSE P5U.Out0[FOpCodes.qPUSH]; P5.PushRhs[tb[node].son[2] ! P5.LogHeapFree => IF calltree = t1 THEN RESUME[TRUE, hLex ← P5.GenAnonLex[1]]]; IF double THEN BEGIN P5U.Out0[IF real THEN FOpCodes.qFCOMP ELSE IF signed THEN FOpCodes.qDCOMP ELSE FOpCodes.qDUCOMP]; P5U.PushLitVal[0]; END; IF hLex # NullLex THEN P5.FreeHeapLex[hLex]; SELECT n FROM intOO,intCO => P5U.OutJump[ IF tf THEN jumpNN[relL] ELSE jumpNN[relGE],label]; intOC,intCC => P5U.OutJump[ IF tf THEN jumpNN[relLE] ELSE jumpNN[relG],label]; ENDCASE; P5U.InsertLabel[fail]; RETURN END; ENDCASE END; ENDCASE END; CatchMark: PUBLIC PROCEDURE [node: Tree.Index] = BEGIN -- process a CONTINUEd or RETRYed statement savCRlabel: CRLRIndex ← CRlabel; l: CRLRIndex ← P5U.GetChunk[SIZE[CRLabelRecord]]; elabel: LabelCCIndex; CRlabel ← l; cb[l].free ← FALSE; P5U.InsertLabel[cb[l].retrylabel ← P5U.LabelAlloc[]]; elabel ← cb[l].contlabel ← P5U.LabelAlloc[]; cb[l].crcc ← CPtr.catchcount; tb[node].son[1] ← P5.StatementTree[tb[node].son[1]]; P5U.InsertLabel[elabel]; CRlabel ← savCRlabel; P5U.FreeChunk[l, SIZE[CRLabelRecord]]; RETURN END; Label: PUBLIC PROCEDURE [node: Tree.Index] = BEGIN -- process an exitable block elabel: LabelCCIndex ← P5U.LabelAlloc[]; labelmark: EXLRIndex ← labelStack; TreeOps.ScanList[tb[node].son[2], LabelCreate]; tb[node].son[1] ← P5.StatementTree[tb[node].son[1]]; P5U.OutJump[Jump, elabel]; LabelList[tb[node].son[2], elabel]; P5U.InsertLabel[elabel]; PopLabels[labelmark]; RETURN END; GetLabelMark: PUBLIC PROCEDURE RETURNS [EXLRIndex] = BEGIN RETURN[labelStack] END; PopLabels: PUBLIC PROCEDURE [labelmark: EXLRIndex] = BEGIN oldl: EXLRIndex; UNTIL labelStack = labelmark DO oldl ← labelStack; labelStack ← cb[labelStack].thread; P5U.FreeChunk[oldl, SIZE[EXLabelRecord]]; ENDLOOP; RETURN END; LabelList: PUBLIC PROCEDURE [t: Tree.Link, elabel: LabelCCIndex] = BEGIN -- generates code for labels Clabelitem: PROCEDURE [t: Tree.Link] = BEGIN -- generates code for a labelitem WITH t SELECT FROM subtree => BEGIN TreeOps.ScanList[tb[index].son[1], PutLabel]; tb[index].son[2] ← P5.StatementTree[tb[index].son[2]]; P5U.OutJump[Jump, elabel]; RETURN END; ENDCASE END; TreeOps.ScanList[t, Clabelitem]; RETURN END; PutLabel: PROCEDURE [t: Tree.Link] = BEGIN WITH t SELECT FROM hash => P5U.InsertLabel[cb[FindLabel[index]].labelcci]; ENDCASE; RETURN END; LabelCreate: PUBLIC PROCEDURE [t: Tree.Link] = BEGIN -- sets up label cells for labels WITH t SELECT FROM subtree => TreeOps.ScanList[tb[index].son[1], PushLabel]; ENDCASE; RETURN END; PushLabel: PROCEDURE [t: Tree.Link] = BEGIN -- stacks a label for an EXIT clause l: EXLRIndex ← P5U.GetChunk[SIZE[EXLabelRecord]]; WITH t SELECT FROM hash => BEGIN cb[l] ← EXLabelRecord[free: FALSE, thread: labelStack, labelhti: index, labelcc: CPtr.catchcount, labelcci: P5U.LabelAlloc[]]; labelStack ← l; RETURN; END; ENDCASE END; MakeExitLabel: PUBLIC PROCEDURE RETURNS [exit, loop: LabelCCIndex] = BEGIN -- sets up anonymous label for EXITs l: EXLRIndex ← P5U.GetChunk[SIZE[EXLabelRecord]]; exit ← P5U.LabelAlloc[]; loop ← P5U.LabelAlloc[]; cb[l] ← EXLabelRecord[free: FALSE, thread: labelStack, labelhti: HTNull, labelcc: CPtr.catchcount, labelcci: loop]; labelStack ← l; l ← P5U.GetChunk[SIZE[EXLabelRecord]]; cb[l] ← EXLabelRecord[free: FALSE, thread: labelStack, labelhti: HTNull, labelcc: CPtr.catchcount, labelcci: exit]; labelStack ← l; RETURN END; FindLabel: PROCEDURE [hti: HTIndex] RETURNS [c: EXLRIndex] = BEGIN -- searches down label stack for label hti FOR c ← labelStack, cb[c].thread UNTIL c = EXLRNull DO IF cb[c].labelhti = hti THEN RETURN ENDLOOP; SIGNAL UndeclaredLabel[hti]; RETURN END; Retry: PUBLIC PROCEDURE = BEGIN -- process RETRY statement RetContExit[cb[CRlabel].crcc, cb[CRlabel].retrylabel]; RETURN END; Continue: PUBLIC PROCEDURE = BEGIN -- process CONTINUE statement RetContExit[cb[CRlabel].crcc, cb[CRlabel].contlabel]; RETURN END; Exit: PUBLIC PROCEDURE = BEGIN -- generate code for EXIT l: EXLRIndex ← FindLabel[HTNull]; RetContExit[cb[l].labelcc, cb[l].labelcci]; RETURN END; Loop: PUBLIC PROCEDURE = BEGIN -- generate code for EXIT l: EXLRIndex ← FindLabel[HTNull]; l ← cb[l].thread; RetContExit[cb[l].labelcc, cb[l].labelcci]; RETURN END; GoTo: PUBLIC PROCEDURE [node: Tree.Index] = BEGIN -- generate code for GOTO l: EXLRIndex; WITH tb[node].son[1] SELECT FROM hash => l ← FindLabel[index]; ENDCASE; RetContExit[cb[l].labelcc, cb[l].labelcci]; RETURN END; RetContExit: PROCEDURE [cc: CARDINAL, lc: LabelCCIndex] = BEGIN -- process EXIT/REPEAT statement IF CPtr.catchcount = cc THEN P5U.OutJump[Jump, lc] ELSE BEGIN var: VarComponent ← [wSize: 1, space: frame[ wd: ControlDefs.localbase, level: CPtr.curctxlvl-(CPtr.catchcount-cc-1)]]; P5L.LoadComponent[var]; P5U.PushLitVal[-1]; P5U.Out1[FOpCodes.qLL, ControlDefs.returnOffset]; P5U.Out0[FOpCodes.qSFC]; Stack.Decr[2]; P5U.OutJump[Jump, lc]; END; RETURN END; END...