-- CgenUtil.mesa, last modified by Sweet, November 28, 1979 10:04 AM DIRECTORY AltoDefs: FROM "altodefs" USING [Address, BYTE, wordlength], Code: FROM "code" USING [ CodePassInconsistency, codeptr, fileindex, stking, xtracting, xtractsei, ZEROlexeme], CodeDefs: FROM "codedefs" USING [ CCIndex, CCItem, CCNull, ChunkIndex, CodeCCIndex, CodeChunkType, JumpCCIndex, JumpCCNull, JumpType, LabelCCIndex, LabelCCNull, Lexeme, NULLfileindex], ComData: FROM "comdata" USING [typeSTRING], ControlDefs: FROM "controldefs" USING [FrameVec], FOpCodes: FROM "fopcodes" USING [qJ, qJREL, qLI], LiteralOps: FROM "literalops" USING [Find, Value], MiscDefs: FROM "miscdefs" USING [CallDebugger], OpTableDefs: FROM "optabledefs" USING [instlength], P5: FROM "p5" USING [NumberOfParams, P5Error, PushEffect], P5U: FROM "p5u", Stack: FROM "stack" USING [Check, Depth], SymbolOps: FROM "symbolops" USING [ NextSe, RecordRoot, UnderType, WordsForType], Symbols: FROM "symbols" USING [ BitAddress, bodyType, BTIndex, BTNull, CBTIndex, ContextLevel, CSEIndex, CSENull, CTXIndex, ctxType, HTIndex, HTNull, ISEIndex, ISENull, lG, lL, MDIndex, RecordSEIndex, RecordSENull, SEIndex, SENull, seType, typeTYPE], SymbolSegment: FROM "symbolsegment" USING [ByteIndex], SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, FreeHeapNode], Table: FROM "table" USING [Base, FreeChunk, GetChunk, Notifier], Tree: FROM "tree" USING [Index, Link, Null, NullIndex, treeType], TreeOps: FROM "treeops" USING [ScanList]; CgenUtil: PROGRAM IMPORTS MPtr: ComData, CPtr: Code, CodeDefs, LiteralOps, MiscDefs, OpTableDefs, P5, Stack, SymbolOps, SystemDefs, Table, TreeOps EXPORTS CodeDefs, P5U = BEGIN OPEN SymbolOps, CodeDefs; -- imported definitions Address: TYPE = AltoDefs.Address; BYTE: TYPE = AltoDefs.BYTE; wordlength: CARDINAL = AltoDefs.wordlength; BitAddress: TYPE = Symbols.BitAddress; BTIndex: TYPE = Symbols.BTIndex; CBTIndex: TYPE = Symbols.CBTIndex; BTNull: BTIndex = Symbols.BTNull; ContextLevel: TYPE = Symbols.ContextLevel; CSEIndex: TYPE = Symbols.CSEIndex; CSENull: CSEIndex = Symbols.CSENull; CTXIndex: TYPE = Symbols.CTXIndex; HTIndex: TYPE = Symbols.HTIndex; HTNull: HTIndex = Symbols.HTNull; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; lG: ContextLevel = Symbols.lG; lL: ContextLevel = Symbols.lL; MDIndex: TYPE = Symbols.MDIndex; RecordSEIndex: TYPE = Symbols.RecordSEIndex; RecordSENull: RecordSEIndex = Symbols.RecordSENull; SEIndex: TYPE = Symbols.SEIndex; SENull: SEIndex = Symbols.SENull; typeTYPE: CSEIndex = Symbols.typeTYPE; tb: Table.Base; -- tree base (local copy) seb: Table.Base; -- semantic entry base (local copy) ctxb: Table.Base; -- context entry base (local copy) bb: Table.Base; -- body entry base (local copy) cb: Table.Base; -- code base (local copy) CgenUtilNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; bb ← base[Symbols.bodyType]; cb ← tb ← base[Tree.treeType]; RETURN END; codeindex: SymbolSegment.ByteIndex; AllocCodeCCItem: PUBLIC PROCEDURE [n: [0..3]] RETURNS [c: CodeCCIndex] = BEGIN c ← GetChunk[SIZE[code CCItem] + n]; cb[c] ← CCItem[free: FALSE, pad:0, flink: CCNull, blink: CCNull, ccvalue: code[inst: 0, realinst: FALSE, minimalStack: FALSE, sourcefileindex: NULLfileindex, isize: 0, aligned: FALSE, fill: 0, parameters: ]]; IF CPtr.stking THEN cb[c].sourcefileindex ← codeindex; linkCCItem[c]; RETURN END; BitsForOperand: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [CARDINAL] = BEGIN WITH t SELECT FROM literal => RETURN [wordlength]; -- not always TRUE, but good enough ENDCASE; RETURN[BitsForType[OperandType[t]]] END; BitsForType: PUBLIC PROCEDURE [sei: SEIndex] RETURNS [CARDINAL] = BEGIN csei: CSEIndex ← UnderType[sei]; WITH seb[csei] SELECT FROM record => RETURN[length]; ENDCASE => RETURN[SymbolOps.WordsForType[csei]*wordlength] END; CCellAlloc: PUBLIC PROCEDURE [t: CodeChunkType] = BEGIN -- allocates a cell for other than code or label c: CCIndex; nwords: CARDINAL; codeindex ← MAX[CPtr.fileindex, codeindex]; SELECT t FROM code => P5.P5Error[262]; label => P5.P5Error[263]; jump => nwords ← SIZE[jump CCItem]; other => nwords ← SIZE[other CCItem]; ENDCASE; c ← GetChunk[nwords]; SELECT t FROM jump => cb[c] ← CCItem[free: FALSE, pad:0, flink: , blink: , ccvalue: jump[,,,,,,,]]; other => cb[c] ← CCItem[free: FALSE, pad:0, flink: , blink: , ccvalue: other[obody: ]]; ENDCASE; linkCCItem[c]; RETURN END; CgenUtilInit: PUBLIC PROCEDURE = BEGIN CPtr.ZEROlexeme ← Lexeme[literal[word[LiteralOps.Find[0]]]]; codeindex ← CPtr.fileindex ← 0; END; ComputeFrameSize: PUBLIC PROCEDURE [fs: CARDINAL] RETURNS [CARDINAL] = BEGIN -- finds alloc-vector index for frame of size fs OPEN ControlDefs; fx: CARDINAL; FOR fx IN [0..LENGTH[FrameVec]) DO IF fs <= FrameVec[fx] THEN RETURN [fx] ENDLOOP; ERROR; END; CreateLabel: PUBLIC PROCEDURE RETURNS [c: LabelCCIndex] = BEGIN -- allocates and inserts a label at codeptr c ← LabelAlloc[]; InsertLabel[c]; RETURN END; DeleteCell: PUBLIC PROCEDURE [c: CCIndex] = BEGIN -- deletes cell from code stream nwords: CARDINAL; IF cb[c].blink # CCNull THEN cb[cb[c].blink].flink ← cb[c].flink; IF cb[c].flink # CCNull THEN cb[cb[c].flink].blink ← cb[c].blink; WITH cb[c] SELECT FROM code => nwords ← ParamCount[LOOPHOLE[c]] + SIZE[code CCItem]; label => nwords ← SIZE[label CCItem]; jump => nwords ← SIZE[jump CCItem]; other => nwords ← SIZE[other CCItem]; ENDCASE; FreeChunk[c, nwords]; RETURN END; EnumerateCaseArms: PUBLIC PROCEDURE [node: Tree.Index, action: PROCEDURE [t: Tree.Link]] = BEGIN ProcessItem: PROCEDURE [t: Tree.Link] = BEGIN inode: Tree.Index; WITH t SELECT FROM subtree => inode ← index; ENDCASE; SELECT tb[inode].name FROM item => action[tb[inode].son[2]]; caseswitch => TreeOps.ScanList[tb[inode].son[3], ProcessItem]; ENDCASE; END; TreeOps.ScanList[tb[node].son[2], ProcessItem]; IF tb[node].son[3] # Tree.Null THEN action[tb[node].son[3]]; END; FieldAddress: PUBLIC PROCEDURE [sei: ISEIndex] RETURNS [BitAddress, CARDINAL] = BEGIN RETURN [seb[sei].idValue, seb[sei].idInfo] END; FreeChunk: PUBLIC PROCEDURE [i: CodeDefs.ChunkIndex, size: CARDINAL] = BEGIN p: POINTER TO MonitorRecord; FOR p ← monList, p.next WHILE p # NIL DO IF p.cell = i AND p.action = free THEN MiscDefs.CallDebugger["From FreeChunk"L]; ENDLOOP; Table.FreeChunk[LOOPHOLE[i],size]; END; FullWordBits: PUBLIC PROCEDURE [bits: CARDINAL] RETURNS [CARDINAL] = BEGIN RETURN[((bits+wordlength-1)/wordlength) * wordlength] END; GetChunk: PUBLIC PROCEDURE [size: CARDINAL] RETURNS [c: CodeDefs.ChunkIndex] = BEGIN p: POINTER TO MonitorRecord; c ← LOOPHOLE[Table.GetChunk[size]]; FOR p ← monList, p.next WHILE p # NIL DO IF p.cell = c AND p.action = allocate THEN MiscDefs.CallDebugger["From GetChunk"L]; ENDLOOP; RETURN [c]; END; InsertLabel: PUBLIC PROCEDURE [c: LabelCCIndex] = BEGIN -- puts a label chunk in the code stream IF CPtr.codeptr # CCNull THEN BEGIN cb[c].flink ← cb[CPtr.codeptr].flink; IF cb[CPtr.codeptr].flink # CCNull THEN cb[cb[CPtr.codeptr].flink].blink ← c; cb[CPtr.codeptr].flink ← c; END ELSE cb[c].flink ← CCNull; cb[c].blink ← CPtr.codeptr; CPtr.codeptr ← c; RETURN END; LabelAlloc: PUBLIC PROCEDURE RETURNS [c: LabelCCIndex] = BEGIN -- gets a chunk for a label but does not insert it in stream c ← GetChunk[SIZE[label CCItem]]; cb[c] ← CCItem[free: FALSE, pad:0, flink: , blink: , ccvalue: label[labelseen: FALSE, labelinfo: generating[filltoword: , jumplist: JumpCCNull]]]; RETURN END; linkCCItem: PROCEDURE[c: CCIndex] = BEGIN -- inserts a CCItem in list @ codeptr IF CPtr.codeptr # CCNull THEN BEGIN cb[c].flink ← cb[CPtr.codeptr].flink; IF cb[CPtr.codeptr].flink # CCNull THEN cb[cb[CPtr.codeptr].flink].blink ← c; cb[CPtr.codeptr].flink ← c; END ELSE cb[c].flink ← CCNull; cb[c].blink ← CPtr.codeptr; CPtr.codeptr ← c; RETURN END; LongTreeAddress: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [long: BOOLEAN] = BEGIN node: Tree.Index; WITH t SELECT FROM subtree => BEGIN node ← index; IF node = Tree.NullIndex THEN long ← FALSE ELSE SELECT tb[node].name FROM loophole, cast, openx, pad, chop => long ← LongTreeAddress[tb[node].son[1]]; dot, uparrow, dindex, seqindex, dollar, index, reloc => long ← tb[node].attr2; assignx => WITH tb[node].son[2] SELECT FROM subtree => IF tb[index].name = mwconst THEN long ← LongTreeAddress[tb[node].son[1]] ELSE long ← LongTreeAddress[tb[node].son[2]]; ENDCASE => long ← LongTreeAddress[tb[node].son[2]]; ifx => long ← LongTreeAddress[tb[node].son[2]] OR LongTreeAddress[tb[node].son[3]]; casex => BEGIN LongArm: PROCEDURE [t: Tree.Link] = BEGIN long ← long OR LongTreeAddress[t]; END; long ← FALSE; EnumerateCaseArms[node, LongArm]; END; ENDCASE => long ← FALSE; END; ENDCASE => long ← FALSE; RETURN END; MakeTreeLiteral: PUBLIC PROCEDURE [val: WORD] RETURNS [Tree.Link] = BEGIN RETURN [Tree.Link[literal[[word[index: LiteralOps.Find[val]]]]]] END; MonitorAction: TYPE = {allocate, free}; MonitorRecord: TYPE = RECORD [next: POINTER TO MonitorRecord, cell: CCIndex, action: MonitorAction]; monList: POINTER TO MonitorRecord ← NIL; Monitor: PROCEDURE [cell: CCIndex, action: MonitorAction] = BEGIN p: POINTER TO MonitorRecord; p ← SystemDefs.AllocateHeapNode[SIZE[MonitorRecord]]; p↑ ← [monList, cell, action]; monList ← p; END; NextVar: PUBLIC PROCEDURE [sei: ISEIndex] RETURNS [ISEIndex] = BEGIN -- starting at sei returns first variable on ctx-list IF sei = ISENull THEN RETURN [ISENull]; DO IF seb[sei].idType # typeTYPE THEN RETURN [sei]; IF (sei ← SymbolOps.NextSe[sei]) = ISENull THEN EXIT; ENDLOOP; RETURN [ISENull]; END; OperandType: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [sei: CSEIndex] = BEGIN -- compute number of words for storing value of tree WITH e:t SELECT FROM literal => WITH e.info SELECT FROM string => sei ← MPtr.typeSTRING; ENDCASE => SIGNAL CPtr.CodePassInconsistency; symbol => sei ← UnderType[seb[e.index].idType]; subtree => IF e = Tree.Null THEN IF CPtr.xtracting THEN sei ← UnderType[seb[CPtr.xtractsei].idType] ELSE ERROR ELSE sei ← tb[e.index].info; ENDCASE; RETURN END; Out0: PUBLIC PROCEDURE [i: BYTE] = BEGIN -- outputs an parameter-less instruction c: CodeCCIndex; pusheffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 0 THEN P5.P5Error[257]; codeindex ← MAX[CPtr.fileindex, codeindex]; c ← AllocCodeCCItem[0]; cb[c].inst ← i; cb[c].minimalStack ← Stack.Depth[] = pusheffect; RETURN END; Out1: PUBLIC PROCEDURE [i: BYTE, p1: WORD] = BEGIN -- outputs an one-parameter instruction c: CodeCCIndex; pusheffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 1 THEN P5.P5Error[258]; codeindex ← MAX[CPtr.fileindex, codeindex]; c ← AllocCodeCCItem[1]; cb[c].inst ← i; cb[c].parameters[1] ← p1; cb[c].minimalStack ← Stack.Depth[] = pusheffect; RETURN END; Out2: PUBLIC PROCEDURE [i: BYTE, p1, p2: WORD] = BEGIN -- outputs an two-parameter instruction c: CodeCCIndex; pusheffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 2 THEN P5.P5Error[259]; codeindex ← MAX[CPtr.fileindex, codeindex]; c ← AllocCodeCCItem[2]; cb[c].inst ← i; cb[c].parameters[1] ← p1; cb[c].parameters[2] ← p2; cb[c].minimalStack ← Stack.Depth[] = pusheffect; RETURN END; Out3: PUBLIC PROCEDURE [i: BYTE, p1, p2, p3: WORD] = BEGIN -- outputs an three-parameter instruction c: CodeCCIndex; pusheffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 3 THEN P5.P5Error[260]; codeindex ← MAX[CPtr.fileindex, codeindex]; c ← AllocCodeCCItem[3]; cb[c].inst ← i; cb[c].parameters[1] ← p1; cb[c].parameters[2] ← p2; cb[c].parameters[3] ← p3; cb[c].minimalStack ← Stack.Depth[] = pusheffect; RETURN END; OutJump: PUBLIC PROCEDURE [jt: JumpType, l: LabelCCIndex] = BEGIN -- outputs a jump-type code ceel into the code stream SELECT jt FROM Jump, JumpA, JumpC, JumpCA, JumpRet => Stack.Check[FOpCodes.qJ]; ENDCASE => Stack.Check[FOpCodes.qJREL]; CCellAlloc[jump]; WITH cb[CPtr.codeptr] SELECT FROM jump => BEGIN fixedup ← FALSE; completed ← FALSE; jtype ← jt; destlabel ← l; IF l # LabelCCNull THEN BEGIN thread ← cb[l].jumplist; cb[l].jumplist ← LOOPHOLE[CPtr.codeptr, JumpCCIndex]; END ELSE thread ← JumpCCNull; RETURN END; ENDCASE END; ParamCount: PUBLIC PROCEDURE [c: CodeCCIndex] RETURNS [CARDINAL] = BEGIN RETURN[IF cb[c].isize # 0 THEN cb[c].isize-1 ELSE IF cb[c].realinst THEN OpTableDefs.instlength[cb[c].inst]-1 ELSE P5.NumberOfParams[cb[c].inst]] END; PrevVar: PUBLIC PROCEDURE [ssei, sei : ISEIndex] RETURNS [ISEIndex] = BEGIN -- returns vars in reverse order as those returned by nextvar psei: ISEIndex ← NextVar[ssei]; rsei: ISEIndex; IF psei = sei THEN RETURN [psei]; UNTIL psei = sei DO rsei ← psei; psei ← NextVar[SymbolOps.NextSe[psei]]; ENDLOOP; RETURN [rsei]; END; PushLitVal: PUBLIC PROCEDURE [v: UNSPECIFIED] = BEGIN -- forces a constant onto the stack Out1[FOpCodes.qLI, v]; RETURN END; SetCodeIndex: PUBLIC PROCEDURE [i: SymbolSegment.ByteIndex] = BEGIN codeindex ← i; END; TreeLiteral: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [BOOLEAN] = BEGIN node: Tree.Index; DO WITH t SELECT FROM literal => RETURN[info.litTag = word]; subtree => BEGIN node ← index; SELECT tb[node].name FROM cast, mwconst => t ← tb[node].son[1]; ENDCASE => RETURN [FALSE]; END; ENDCASE => RETURN[FALSE] ENDLOOP END; TreeLiteralValue: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [WORD] = BEGIN node: Tree.Index; DO WITH e:t SELECT FROM literal => WITH e.info SELECT FROM word => RETURN [LiteralOps.Value[index]]; ENDCASE => EXIT; subtree => BEGIN node ← e.index; SELECT tb[node].name FROM cast, mwconst => t ← tb[node].son[1]; ENDCASE => EXIT; END; ENDCASE => EXIT ENDLOOP; P5.P5Error[261]; -- never comes back RETURN[0] END; UnMonitor: PROCEDURE [cell: CCIndex, action: MonitorAction] = BEGIN p, q: POINTER TO MonitorRecord; IF monList = NIL THEN RETURN; IF monList.cell = cell AND monList.action = action THEN BEGIN p ← monList.next; SystemDefs.FreeHeapNode[monList]; monList ← p; END; FOR p ← monList, p.next UNTIL p.next = NIL DO IF p.next.cell = cell AND p.next.action = action THEN BEGIN q ← p.next.next; SystemDefs.FreeHeapNode[p.next]; p.next ← q; RETURN; END; ENDLOOP; END; WordAligned: PUBLIC PROCEDURE [tsei: RecordSEIndex] RETURNS [BOOLEAN] = BEGIN -- sees if a word-aligned record (never TRUE for a variant record) -- always true for an argument record sei: ISEIndex; wa: INTEGER ← 0; a: BitAddress; tsei ← RecordRoot[tsei]; IF seb[tsei].hints.variant THEN RETURN[FALSE]; IF seb[tsei].argument THEN RETURN[TRUE]; sei ← NextVar[ctxb[seb[tsei].fieldCtx].seList]; UNTIL sei = ISENull DO a ← seb[sei].idValue; IF a.bd # 0 THEN RETURN[FALSE]; IF a.wd < wa THEN RETURN [FALSE]; wa ← a.wd; sei ← NextVar[NextSe[sei]]; ENDLOOP; RETURN[TRUE] END; WordsForOperand: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [n: CARDINAL] = BEGIN -- compute number of words for storing value of tree WITH t SELECT FROM literal => n ← 1; -- multiwords will be subtrees symbol => n ← WordsForSei[seb[index].idType]; subtree => n ← WordsForType[OperandType[t]]; ENDCASE; RETURN END; WordsForSei: PUBLIC PROCEDURE [sei: SEIndex] RETURNS [CARDINAL] = BEGIN RETURN [IF sei = SENull THEN 0 ELSE SymbolOps.WordsForType[UnderType[sei]]]; END; END.