-- file Pass4Xa.Mesa -- last written by Satterthwaite, January 17, 1980 3:15 PM DIRECTORY AltoDefs: FROM "altodefs" USING [charlength, maxinteger, maxword, wordlength], ComData: FROM "comdata" USING [ownSymbols, switches, typeINTEGER, typeCHARACTER], InlineDefs: FROM "inlinedefs" USING [BITAND, BITOR, BITSHIFT], Literals: FROM "literals" USING [LitDescriptor, ltType], LiteralOps: FROM "literalops" USING [FindDescriptor, MasterString], Log: FROM "log" USING [Error, ErrorN, ErrorTree], P4: FROM "p4" USING [ Covering, Repr, none, signed, unsigned, both, other, RegCount, MaxRegs, AdjustBias, BiasForType, BitsForType, CatchNest, ComputeIndexRegs, Exp, ForceType, MakeStructuredLiteral, MakeTreeLiteral, OperandType, RegsForType, RepForType, RValue, StructuredLiteral, TreeLiteral, TreeLiteralDesc, TreeLiteralValue, TypeExp, VBias, VPop, VPush, VRegs, VRep, WordsForType, ZeroP], Symbols: FROM "symbols" USING [ctxType, seType, BitAddress, SEIndex, ISEIndex, CSEIndex, ArraySEIndex, RecordSEIndex, typeANY, lZ], SymbolOps: FROM "symbolops" USING [ Cardinality, FirstVisibleSe, FnField, NextSe, NormalType, RecordRoot, UnderType], SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, FreeHeapNode], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [Index, Link, Map, Scan, Null, treeType], TreeOps: FROM "treeops" USING [ FreeNode, GetNode, ListLength, PopTree, PushTree, PushLit, PushNode, ScanList, SetAttr, SetInfo, TestTree, UpdateList], Types: FROM "types" USING [Assignable]; Pass4Xa: PROGRAM IMPORTS InlineDefs, Log, LiteralOps, P4, SymbolOps, SystemDefs, TreeOps, Types, dataPtr: ComData EXPORTS P4 = BEGIN OPEN SymbolOps, TreeOps, P4; -- pervasive definitions from Symbols SEIndex: TYPE = Symbols.SEIndex; ISEIndex: TYPE = Symbols.ISEIndex; CSEIndex: TYPE = Symbols.CSEIndex; RecordSEIndex: TYPE = Symbols.RecordSEIndex; BitAddress: TYPE = Symbols.BitAddress; tb: Table.Base; -- tree base address (local copy) ltb: Table.Base; -- literal base address (local copy) seb: Table.Base; -- se table base address (local copy) ctxb: Table.Base; -- context table base address (local copy) ExpANotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked tb ← base[Tree.treeType]; ltb ← base[Literals.ltType]; seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; END; -- expression list manipulation MakeRecord: PROCEDURE [record: RecordSEIndex, expList: Tree.Link] RETURNS [val: Tree.Link, nRegs: RegCount] = BEGIN sei: ISEIndex; const: BOOLEAN; subNode: Tree.Index; EvaluateField: Tree.Map = BEGIN type: CSEIndex = UnderType[seb[sei].idType]; IF t = Tree.Null THEN BEGIN v ← Tree.Null; IF BitsForType[type] # 0 THEN const ← FALSE; END ELSE BEGIN v ← WITH t SELECT FROM subtree => SELECT tb[index].name FROM construct => NestedConstruct[index, type], union => Union[index, TRUE], ENDCASE => Rhs[t, type], ENDCASE => Rhs[t, type]; IF ~TreeLiteral[v] THEN WITH v SELECT FROM subtree => SELECT tb[index].name FROM mwconst => NULL; union => IF ~tb[index].attr1 THEN const ← FALSE; ENDCASE => const ← FALSE; ENDCASE => const ← FALSE; nRegs ← MAX[VRegs[], nRegs]; VPop[]; END; sei ← NextSe[sei]; RETURN END; sei ← FirstVisibleSe[seb[record].fieldCtx]; const ← TRUE; nRegs ← 0; val ← UpdateList[expList, EvaluateField]; IF TestTree[val, list] THEN BEGIN subNode ← GetNode[val]; tb[subNode].attr1 ← const END; RETURN END; NestedConstruct: PROCEDURE [node: Tree.Index, lType: CSEIndex] RETURNS [val: Tree.Link] = BEGIN rType: CSEIndex = tb[node].info; val ← Construct[node, TRUE]; IF WordsForType[lType] > WordsForType[rType] THEN val ← PadRecord[val, lType]; RETURN END; MakeArgRecord: PUBLIC PROCEDURE [record: RecordSEIndex, expList: Tree.Link] RETURNS [val: Tree.Link] = BEGIN type: CSEIndex; seb[record].lengthUsed ← TRUE; SELECT TRUE FROM (expList = Tree.Null) => val ← Tree.Null; TestTree[expList, list] => val ← MakeRecord[record, expList].val; ENDCASE => BEGIN type ← UnderType[seb[FirstVisibleSe[seb[record].fieldCtx]].idType]; val ← Rhs[expList, type]; VPop[]; END; RETURN END; -- construction of packed values (machine dependent) WordLength: CARDINAL = AltoDefs.wordlength; ByteLength: CARDINAL = AltoDefs.charlength; FillMultiWord: PROCEDURE [words: DESCRIPTOR FOR ARRAY OF WORD, origin: CARDINAL, t: Tree.Link] RETURNS [newOrigin: CARDINAL] = BEGIN desc: Literals.LitDescriptor; i: CARDINAL; desc ← TreeLiteralDesc[t]; FOR i IN [0 .. desc.length) DO words[origin + i] ← ltb[desc.offset][i] ENDLOOP; RETURN [origin + desc.length] END; PackRecord: PROCEDURE [record: RecordSEIndex, expList: Tree.Link] RETURNS [Tree.Link] = BEGIN n: CARDINAL = WordsForType[record]; root, type: RecordSEIndex; list: Tree.Link; sei: ISEIndex; offset: CARDINAL; words: DESCRIPTOR FOR ARRAY OF WORD; i: CARDINAL; more: BOOLEAN; StoreBits: PROCEDURE [sei: ISEIndex, value: WORD] = BEGIN OPEN InlineDefs; Masks: ARRAY [0..WordLength] OF WORD = [0B, 1B, 3B, 7B, 17B, 37B, 77B, 177B, 377B, 777B, 1777B, 3777B, 7777B, 17777B, 37777B, 77777B, 177777B]; address: BitAddress; size, w, shift: CARDINAL; IF seb[root].argument THEN [address, size] ← FnField[sei] ELSE BEGIN address ← seb[sei].idValue; size ← seb[sei].idInfo END; w ← address.wd; shift ← (WordLength-offset) - (address.bd+size); words[w] ← BITOR[words[w], BITSHIFT[BITAND[value, Masks[size]], shift]]; END; PackField: Tree.Scan = BEGIN node: Tree.Index; address: BitAddress; typeId: ISEIndex; subType: CSEIndex; SELECT TRUE FROM t = Tree.Null => NULL; TreeLiteral[t] => StoreBits[sei, TreeLiteralValue[t]]; ENDCASE => BEGIN node ← GetNode[t]; SELECT tb[node].name FROM mwconst => BEGIN address ← IF seb[root].argument THEN FnField[sei].offset ELSE seb[sei].idValue; [] ← FillMultiWord[words, address.wd, tb[node].son[1]]; END; union => BEGIN WITH tb[node].son[1] SELECT FROM symbol => typeId ← index; ENDCASE => ERROR; subType ← UnderType[seb[sei].idType]; WITH seb[subType] SELECT FROM union => IF controlled THEN StoreBits[tagSei, seb[typeId].idValue]; ENDCASE => ERROR; type ← LOOPHOLE[UnderType[typeId], RecordSEIndex]; list ← tb[node].son[2]; more ← TRUE; END; ENDCASE => ERROR; END; sei ← NextSe[sei]; END; words ← DESCRIPTOR[SystemDefs.AllocateHeapNode[n], n]; FOR i IN [0 .. n) DO words[i] ← 0 ENDLOOP; root ← type ← RecordRoot[record]; offset ← IF seb[record].length < WordLength THEN WordLength - seb[record].length ELSE 0; list ← expList; more ← TRUE; WHILE more DO more ← FALSE; sei ← FirstVisibleSe[seb[type].fieldCtx]; ScanList[list, PackField]; ENDLOOP; PushLit[LiteralOps.FindDescriptor[words]]; PushNode[IF n=1 THEN cast ELSE mwconst, 1]; SetInfo[record]; SystemDefs.FreeHeapNode[BASE[words]]; RETURN [PopTree[]] END; PadRecord: PUBLIC PROCEDURE [t: Tree.Link, lType: CSEIndex] RETURNS [Tree.Link] = BEGIN IF StructuredLiteral[t] THEN BEGIN words: DESCRIPTOR FOR ARRAY OF WORD; w, nW: CARDINAL; node: Tree.Index; nW ← WordsForType[lType]; words ← DESCRIPTOR[SystemDefs.AllocateHeapNode[nW], nW]; FOR w IN [0 .. nW) DO words[w] ← 0 ENDLOOP; IF TreeLiteral[t] THEN words[0] ← TreeLiteralValue[t] ELSE BEGIN node ← GetNode[t]; SELECT tb[node].name FROM mwconst => w ← FillMultiWord[words, 0, tb[node].son[1]]; ENDCASE => ERROR; FreeNode[node]; END; PushLit[LiteralOps.FindDescriptor[words]]; PushNode[mwconst, 1]; SystemDefs.FreeHeapNode[BASE[words]]; END ELSE BEGIN PushTree[t]; PushNode[pad, 1] END; SetInfo[lType]; RETURN [PopTree[]] END; ExtractValue: PROCEDURE [t: Tree.Link, addr: BitAddress, size: CARDINAL, type: CSEIndex] RETURNS [val: Tree.Link] = BEGIN words: DESCRIPTOR FOR ARRAY OF WORD; i: CARDINAL; desc: Literals.LitDescriptor = TreeLiteralDesc[t]; n: CARDINAL = size/WordLength; IF n > 1 THEN BEGIN IF addr.bd # 0 THEN Log.Error[unimplemented]; words ← DESCRIPTOR[SystemDefs.AllocateHeapNode[n], n]; FOR i IN [0 .. n) DO words[i] ← ltb[desc.offset][addr.wd+i] ENDLOOP; PushLit[LiteralOps.FindDescriptor[words]]; PushNode[mwconst, 1]; SetInfo[type]; SystemDefs.FreeHeapNode[BASE[words]]; val ← PopTree[]; END ELSE val ← MakeStructuredLiteral[ InlineDefs.BITSHIFT[ InlineDefs.BITSHIFT[ltb[desc.offset][addr.wd], addr.bd], -(WordLength - size)], type]; RETURN END; UnpackField: PROCEDURE [t: Tree.Link, field: ISEIndex] RETURNS [val: Tree.Link] = BEGIN rType: CSEIndex = OperandType[t]; vType: CSEIndex = UnderType[seb[field].idType]; addr: BitAddress; addr ← seb[field].idValue; WITH r: seb[rType] SELECT FROM record => IF r.length < WordLength THEN addr.bd ← addr.bd + (WordLength - r.length); ENDCASE => ERROR; RETURN [ExtractValue[t, addr, seb[field].idInfo, vType]] END; UnpackElement: PROCEDURE [t: Tree.Link, i: CARDINAL] RETURNS [val: Tree.Link] = BEGIN aType: CSEIndex = OperandType[t]; cType: CSEIndex; addr: BitAddress; nB, nW: CARDINAL; BytesPerWord: CARDINAL = WordLength/ByteLength; WITH a: seb[aType] SELECT FROM array => BEGIN cType ← UnderType[a.componentType]; nB ← BitsForType[cType]; IF nB > ByteLength OR ~a.oldPacked THEN BEGIN nW ← (nB+(WordLength-1))/WordLength; addr ← [wd:i*nW, bd:0]; nB ← nW*WordLength; END ELSE BEGIN addr ← [wd:i/BytesPerWord, bd:(i MOD BytesPerWord)*ByteLength]; nB ← ByteLength; END; END; ENDCASE => ERROR; RETURN [ExtractValue[t, addr, nB, cType]] END; -- operators Call: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [Tree.Link] = BEGIN OPEN tb[node]; type: CSEIndex; son[1] ← Exp[son[1], none]; VPop[]; type ← OperandType[son[1]]; WITH seb[type] SELECT FROM transfer => BEGIN son[2] ← MakeArgRecord[inRecord, son[2]]; VPush[BiasForType[outRecord], RepForType[outRecord], MaxRegs]; END; ENDCASE => ERROR; IF nSons > 2 THEN CatchNest[son[3]]; RETURN [[subtree[index: node]]] END; MiscXfer: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [Tree.Link] = BEGIN type: CSEIndex; SELECT tb[node].name FROM new => BEGIN tb[node].son[1] ← RValue[tb[node].son[1], 0, none]; VPop[]; VPush[0, unsigned, MaxRegs]; END; fork => BEGIN OPEN tb[node]; son[1] ← Exp[son[1], none]; VPop[]; type ← OperandType[son[1]]; WITH seb[type] SELECT FROM transfer => BEGIN son[2] ← MakeArgRecord[inRecord, son[2]]; VPush[0, other, MaxRegs]; END; ENDCASE => ERROR; END; ENDCASE => ERROR; IF tb[node].nSons > 2 THEN CatchNest[tb[node].son[3]]; RETURN [[subtree[index: node]]] END; Construct: PUBLIC PROCEDURE [node: Tree.Index, nested: BOOLEAN] RETURNS [val: Tree.Link] = BEGIN OPEN tb[node]; type: RecordSEIndex = info; record: RecordSEIndex = RecordRoot[type]; nRegs: RegCount; k: RegCount = RegsForType[type]; [son[2], nRegs] ← MakeRecord[record, son[2]]; seb[type].lengthUsed ← TRUE; SELECT TRUE FROM TestTree[son[2], list] OR TestTree[son[2], union] => BEGIN subNode: Tree.Index = GetNode[son[2]]; IF ~tb[subNode].attr1 -- ~all fields constant THEN BEGIN val ← [subtree[index: node]]; nRegs ← MAX[nRegs, k] END ELSE BEGIN val ← PackRecord[type, son[2]]; FreeNode[node]; nRegs ← k; END; VPush[0, other, nRegs]; END; (son[2] = Tree.Null) => BEGIN val ← Tree.Null; VPush[0, other, 0] END; ENDCASE => val ← CastUniList[node, type, nested]; RETURN END; Union: PUBLIC PROCEDURE [node: Tree.Index, nested: BOOLEAN] RETURNS [val: Tree.Link] = BEGIN OPEN tb[node]; vSei: ISEIndex = WITH son[1] SELECT FROM symbol=>index, ENDCASE=>ERROR; type: RecordSEIndex = LOOPHOLE[UnderType[vSei]]; tSei: CSEIndex = UnderType[info]; tagged: BOOLEAN = WITH seb[tSei] SELECT FROM union => controlled, ENDCASE => FALSE; nRegs: RegCount; [son[2], nRegs] ← MakeRecord[type, son[2]]; seb[type].lengthUsed ← TRUE; attr2 ← tagged; SELECT TRUE FROM TestTree[son[2], list] OR TestTree[son[2], union] => BEGIN attr1 ← WITH son[2] SELECT FROM subtree => tb[index].attr1, ENDCASE => FALSE; val ← [subtree[index: node]]; VPush[0, other, nRegs]; END; (son[2] = Tree.Null) => BEGIN attr1 ← TRUE; val ← [subtree[index: node]]; VPush[0, other, 1]; END; ENDCASE => IF WordsForType[type] = 1 AND (~tagged OR seb[vSei].idValue = 0) THEN val ← CastUniList[node, type, nested] ELSE BEGIN attr1 ← StructuredLiteral[son[2]]; val ← [subtree[index: node]]; VPush[0, other, RegsForType[type]]; END; RETURN END; CastUniList: PROCEDURE [node: Tree.Index, type: CSEIndex, nested: BOOLEAN] RETURNS [val: Tree.Link] = BEGIN subNode: Tree.Index; unSafe: BOOLEAN; t: Tree.Link ← tb[node].son[2]; IF (unSafe ← TestTree[t, safen]) THEN BEGIN subNode ← GetNode[t]; t ← tb[subNode].son[1]; tb[subNode].son[1] ← Tree.Null; FreeNode[subNode]; END; tb[node].son[2] ← Tree.Null; FreeNode[node]; val ← ForceType[t, type]; IF unSafe AND nested THEN BEGIN PushTree[val]; PushNode[safen, 1]; SetInfo[type]; val ← PopTree[]; END; VPush[BiasForType[type], RepForType[type], RegsForType[type]]; RETURN END; RowConstruct: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [val: Tree.Link] = BEGIN OPEN tb[node]; aType: Symbols.ArraySEIndex = info; cType: CSEIndex = UnderType[seb[aType].componentType]; n: CARDINAL = Cardinality[seb[aType].indexType]; const, strings, lstrings: BOOLEAN; nRegs: RegCount; l: CARDINAL; EvalElement: Tree.Map = BEGIN IF t = Tree.Null THEN BEGIN v ← Tree.Null; const ← strings ← lstrings ← FALSE END ELSE BEGIN v ← Rhs[t, cType]; nRegs ← MAX[VRegs[], nRegs]; IF TreeLiteral[v] THEN strings ← lstrings ← FALSE ELSE WITH v SELECT FROM subtree => SELECT tb[index].name FROM mwconst => strings ← lstrings ← FALSE; ENDCASE => const ← strings ← lstrings ← FALSE; literal => WITH info SELECT FROM string => BEGIN const ← FALSE; IF LiteralOps.MasterString[index] = index THEN lstrings ← FALSE ELSE strings ← FALSE; END; ENDCASE; ENDCASE => const ← strings ← lstrings ← FALSE; VPop[]; END; RETURN END; w, nW: CARDINAL; words: DESCRIPTOR FOR ARRAY OF WORD; bitsLeft: CARDINAL; bitCount: CARDINAL; PackElement: Tree.Scan = BEGIN node: Tree.Index; IF TreeLiteral[t] THEN BEGIN bitsLeft ← bitsLeft - bitCount; words[w] ← InlineDefs.BITOR[words[w], InlineDefs.BITSHIFT[TreeLiteralValue[t], bitsLeft]]; IF bitsLeft < bitCount THEN BEGIN w ← w+1; bitsLeft ← WordLength END; END ELSE BEGIN node ← GetNode[t]; SELECT tb[node].name FROM mwconst => w ← FillMultiWord[words, w, tb[node].son[1]]; ENDCASE => ERROR; END; END; SELECT (l ← ListLength[son[2]]) FROM = n => NULL; > n => Log.ErrorN[listLong, l-n]; < n => Log.ErrorN[listShort, n-l]; ENDCASE; const ← strings ← lstrings ← TRUE; nRegs ← 0; son[2] ← UpdateList[son[2], EvalElement]; IF const AND l = n THEN BEGIN nW ← WordsForType[aType]; words ← DESCRIPTOR[SystemDefs.AllocateHeapNode[nW], nW]; FOR w IN [0 .. nW) DO words[w] ← 0 ENDLOOP; bitCount ← IF seb[aType].oldPacked AND BitsForType[cType] <= ByteLength THEN ByteLength ELSE WordLength; w ← 0; bitsLeft ← WordLength; ScanList[son[2], PackElement]; FreeNode[node]; PushLit[LiteralOps.FindDescriptor[words]]; PushNode[IF nW = 1 THEN cast ELSE mwconst, 1]; SetInfo[aType]; SystemDefs.FreeHeapNode[BASE[words]]; val ← PopTree[]; nRegs ← RegsForType[aType]; END ELSE BEGIN attr1 ← strings # lstrings; val ← [subtree[index: node]] END; seb[aType].lengthUsed ← TRUE; VPush[0, other, nRegs]; RETURN END; All: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [Tree.Link] = BEGIN OPEN tb[node]; aType: Symbols.ArraySEIndex = info; cType: CSEIndex = UnderType[seb[aType].componentType]; IF son[1] # Tree.Null THEN BEGIN son[1] ← Rhs[son[1], cType]; IF OperandType[son[1]] # cType THEN son[1] ← ForceType[son[1], cType]; VPop[]; END; VPush[0, other, RegsForType[aType]]; seb[aType].lengthUsed ← TRUE; RETURN [[subtree[index: node]]] END; Dollar: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [val: Tree.Link] = BEGIN OPEN tb[node]; rep: Repr; bias: INTEGER; nRegs: RegCount; k: RegCount = RegsForType[info]; son[1] ← Exp[son[1], none]; nRegs ← VRegs[]; VPop[]; son[2] ← Exp[son[2], none]; rep ← VRep[]; bias ← VBias[]; VPop[]; IF ~StructuredLiteral[son[1]] THEN BEGIN val ← [subtree[index: node]]; nRegs ← MAX[nRegs, k] END ELSE WITH son[2] SELECT FROM symbol => BEGIN val ← UnpackField[son[1], index]; FreeNode[node]; nRegs ← k; END; ENDCASE => ERROR; VPush[bias, rep, nRegs]; RETURN END; Index: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [val: Tree.Link] = BEGIN OPEN tb[node]; aType, iType, cType: CSEIndex; next: SEIndex; nRegs: RegCount; son[1] ← Exp[son[1], none]; FOR aType ← OperandType[son[1]], UnderType[next] DO WITH seb[aType] SELECT FROM array => BEGIN iType ← UnderType[indexType]; cType ← UnderType[componentType]; EXIT END; arraydesc => next ← describedType; long => next ← rangeType; ENDCASE => ERROR; ENDLOOP; IF name = dindex THEN BEGIN son[2] ← RValue[son[2], BiasForType[iType], unsigned]; attr1 ← dataPtr.switches['n]; attr3 ← dataPtr.switches['b]; END ELSE son[2] ← Rhs[son[2], iType, TRUE]; SELECT TRUE FROM (TreeLiteral[son[2]] AND TestTree[son[1], all]) => BEGIN subNode: Tree.Index = GetNode[son[1]]; val ← tb[subNode].son[1]; tb[subNode].son[1] ← Tree.Null; FreeNode[node]; nRegs ← RegsForType[cType]; END; (TreeLiteral[son[2]] AND StructuredLiteral[son[1]]) => BEGIN val ← UnpackElement[son[1], TreeLiteralValue[son[2]]]; FreeNode[node]; nRegs ← RegsForType[cType]; END; ENDCASE => BEGIN val ← [subtree[index:node]]; nRegs ← ComputeIndexRegs[node] END; VPop[]; VPop[]; VPush[BiasForType[cType], RepForType[cType], nRegs]; RETURN END; Reloc: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [val: Tree.Link] = BEGIN nRegs: RegCount; type: CSEIndex = tb[node].info; tb[node].son[1] ← RValue[tb[node].son[1], 0, unsigned]; tb[node].son[2] ← RValue[tb[node].son[2], 0, unsigned]; nRegs ← ComputeIndexRegs[node]; VPop[]; VPop[]; IF ~tb[node].attr1 AND ZeroP[tb[node].son[1]] THEN BEGIN subType: CSEIndex = OperandType[tb[node].son[2]]; rType: CSEIndex; PushTree[tb[node].son[2]]; tb[node].son[2] ← Tree.Null; WITH r: seb[subType] SELECT FROM relative => BEGIN rType ← UnderType[r.resultType]; IF tb[node].attr2 AND seb[UnderType[r.offsetType]].typeTag # long THEN BEGIN PushNode[lengthen, 1]; SetAttr[1, FALSE]; SetAttr[2, FALSE]; SetAttr[3, FALSE]; END ELSE PushNode[cast, 1]; END; ENDCASE => ERROR; SetInfo[rType]; PushNode[uparrow, 1]; SetInfo[type]; SetAttr[1, dataPtr.switches['n]]; SetAttr[2, tb[node].attr2]; val ← PopTree[]; FreeNode[node]; END ELSE val ← [subtree[node]]; VPush[BiasForType[type], RepForType[type], nRegs]; END; Assignment: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [Tree.Link] = BEGIN OPEN tb[node]; lhsType: CSEIndex; son[1] ← Exp[son[1], none]; lhsType ← OperandType[son[1]]; son[2] ← Rhs[son[2], lhsType]; VPop[]; RETURN [RewriteAssign[node, lhsType]] END; TargetRep: PUBLIC PROCEDURE [rep: Repr] RETURNS [Repr] = BEGIN RETURN [IF rep = both THEN signed ELSE rep] END; Rhs: PUBLIC PROCEDURE [ exp: Tree.Link, lType: CSEIndex, voidOK: BOOLEAN ← FALSE] RETURNS [val: Tree.Link] = BEGIN lBias: INTEGER = BiasForType[lType]; lRep: Repr = RepForType[lType]; rType: CSEIndex ← OperandType[exp]; rRep: Repr; nw: CARDINAL; val ← RValue[exp, lBias, TargetRep[lRep]]; rRep ← VRep[]; IF ~Types.Assignable[ [dataPtr.ownSymbols, lType], [dataPtr.ownSymbols, rType]] THEN Log.ErrorTree[typeClash, val]; nw ← WordsForType[lType]; IF ~(IF nw = 0 THEN voidOK ELSE WordsForType[rType] = nw) THEN SELECT seb[lType].typeTag FROM record => val ← PadRecord[val, lType]; union => NULL; ENDCASE => Log.ErrorTree[sizeClash, val]; IF (lType = dataPtr.typeINTEGER AND rRep = unsigned) OR ((rType = dataPtr.typeINTEGER AND rRep = signed) AND lRep = unsigned) THEN val ← CheckRange[val, CARDINAL[AltoDefs.maxinteger-lBias]+1, lType] ELSE SELECT seb[lType].typeTag FROM subrange, enumerated, relative => SELECT Cover[lType, lRep, rType, rRep] FROM full => NULL; partial => val ← CheckRange[val, Cardinality[lType], lType]; ENDCASE => IF nw # 0 THEN val ← BoundsFault[val, lType]; basic => IF lType = dataPtr.typeCHARACTER AND (rRep # both OR TreeLiteral[val]) THEN val ← CheckRange[val, Cardinality[lType], lType]; ENDCASE => NULL; RETURN END; Cover: PUBLIC PROCEDURE [lType: CSEIndex, lRep: Repr, rType: CSEIndex, rRep: Repr] RETURNS [Covering] = BEGIN lLb, lUb, rLb, rUb: LONG INTEGER; [lLb, lUb] ← Bounds[lType, lRep]; [rLb, rUb] ← Bounds[rType, rRep]; RETURN [ IF lLb <= rLb THEN IF lUb < rLb THEN none ELSE IF lUb < rUb THEN partial ELSE full ELSE IF lLb <= rUb THEN partial ELSE none] END; Bounds: PROCEDURE [type: CSEIndex, rep: Repr] RETURNS [lb, ub: LONG INTEGER] = BEGIN WITH t: seb[type] SELECT FROM subrange => BEGIN lb ← t.origin; ub ← lb + t.range END; enumerated => BEGIN lb ← 0; ub ← t.nValues-1 END; relative => [lb, ub] ← Bounds[UnderType[t.offsetType], rep]; ENDCASE => SELECT rep FROM signed => BEGIN lb ← -AltoDefs.maxinteger-1; ub ← AltoDefs.maxinteger END; both => BEGIN lb ← 0; ub ← AltoDefs.maxinteger END; ENDCASE => BEGIN lb ← 0; ub ← AltoDefs.maxword END; RETURN END; CheckRange: PROCEDURE [t: Tree.Link, bound: CARDINAL, type: CSEIndex] RETURNS [val: Tree.Link] = BEGIN SELECT TRUE FROM (bound = 0) => val ← t; TreeLiteral[t] => val ← IF TreeLiteralValue[t] >= bound THEN BoundsFault[t,type] ELSE t; dataPtr.switches['b] => BEGIN PushTree[MakeTreeLiteral[bound]]; IF TestTree[t, safen] THEN BEGIN node: Tree.Index = GetNode[t]; PushTree[tb[node].son[1]]; PushNode[check, -2]; SetInfo[type]; tb[node].son[1] ← PopTree[]; val ← t; END ELSE BEGIN PushTree[t]; PushNode[check, -2]; SetInfo[type]; val ← PopTree[]; END; END; ENDCASE => val ← t; RETURN END; BoundsFault: PROCEDURE [t: Tree.Link, type: CSEIndex] RETURNS [Tree.Link] = BEGIN Log.ErrorTree[boundsFault, AdjustBias[t, -BiasForType[type]]]; PushTree[t]; PushTree[MakeTreeLiteral[0]]; PushNode[check, 2]; SetInfo[type]; RETURN [PopTree[]] END; PushAssignment: PUBLIC PROCEDURE [id, val: Tree.Link, type: CSEIndex] = BEGIN rewrite: BOOLEAN; i, n: CARDINAL; rewrite ← TRUE; WITH val SELECT FROM subtree => SELECT tb[index].name FROM body, signalinit => rewrite ← FALSE; ENDCASE => NULL; ENDCASE => NULL; ScanList[id, PushTree]; n ← ListLength[id]; PushTree[val]; FOR i IN [1 .. n] DO IF i = n THEN PushNode[assign, 2] ELSE BEGIN PushNode[assignx, 2]; SetInfo[type] END; IF rewrite THEN PushTree[RewriteAssign[GetNode[PopTree[]], type]] ELSE SetAttr[1, FALSE]; ENDLOOP; END; RewriteAssign: PROCEDURE [node: Tree.Index, lType: CSEIndex] RETURNS [Tree.Link] = BEGIN IF (tb[node].attr1 ← seb[lType].typeTag = union) THEN BEGIN WITH tb[node].son[1] SELECT FROM subtree => BEGIN subType: CSEIndex; subNode: Tree.Index = index; SELECT tb[subNode].name FROM dot => BEGIN subType ← OperandType[tb[subNode].son[1]]; PushTree[tb[subNode].son[1]]; PushNode[uparrow, 1]; SetInfo[WITH seb[subType] SELECT FROM pointer => UnderType[refType], ENDCASE => Symbols.typeANY]; tb[subNode].son[1] ← PopTree[]; tb[subNode].name ← dollar; END; dollar => NULL; ENDCASE => NULL; -- flagged by code generators for now END; ENDCASE => NULL; -- flagged by code generators for now END; IF tb[node].name = assignx THEN tb[node].info ← OperandType[tb[node].son[1]]; RETURN [[subtree[index: node]]] END; -- misc addressing operators AddrOp: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [val: Tree.Link] = BEGIN nRegs: RegCount; SELECT tb[node].name FROM addr => val ← Addr[node]; base => BEGIN tb[node].son[1] ← Exp[tb[node].son[1], none]; nRegs ← VRegs[]; VPop[]; VPush[0, unsigned, nRegs]; val ← [subtree[index: node]]; END; length => BEGIN type: CSEIndex; tb[node].son[1] ← Exp[tb[node].son[1], none]; type ← OperandType[tb[node].son[1]]; WITH seb[type] SELECT FROM array => BEGIN val ← MakeTreeLiteral[Cardinality[indexType]]; FreeNode[node]; nRegs ← 1; END; ENDCASE => BEGIN val ← [subtree[index: node]]; nRegs ← VRegs[] END; VPop[]; VPush[0, both, nRegs]; END; arraydesc => BEGIN subNode: Tree.Index = GetNode[tb[node].son[1]]; type: CSEIndex = tb[node].info; tb[subNode].son[1] ← RValue[tb[subNode].son[1], 0, unsigned]; nRegs ← VRegs[]; tb[subNode].son[2] ← RValue[tb[subNode].son[2], 0, none]; nRegs ← MAX[VRegs[], nRegs]; IF tb[subNode].son[3] # Tree.Null THEN TypeExp[tb[subNode].son[3]]; VPop[]; VPop[]; IF StructuredLiteral[tb[subNode].son[1]] AND StructuredLiteral[tb[subNode].son[2]] THEN BEGIN n: CARDINAL = WordsForType[type]; words: DESCRIPTOR FOR ARRAY OF WORD; words ← DESCRIPTOR[SystemDefs.AllocateHeapNode[n], n]; [] ← FillMultiWord[ words, FillMultiWord[words, 0, tb[subNode].son[1]], tb[subNode].son[2]]; PushLit[LiteralOps.FindDescriptor[words]]; PushNode[mwconst, 1]; SetInfo[type]; SystemDefs.FreeHeapNode[BASE[words]]; val ← PopTree[]; FreeNode[node]; END ELSE val ← [subtree[index: node]]; VPush[0, other, MAX[RegsForType[type], nRegs]]; END; ENDCASE => BEGIN Log.Error[unimplemented]; VPush[0, none, 0]; val ← [subtree[node]]; END; RETURN END; Addr: PROCEDURE [node: Tree.Index] RETURNS [val: Tree.Link] = BEGIN OPEN tb[node]; subNode: Tree.Index; t, v: Tree.Link; type, next: CSEIndex; nRegs: RegCount; WordSize: CARDINAL = AltoDefs.wordlength; son[1] ← Exp[son[1], none]; nRegs ← MAX[VRegs[], RegsForType[info]]; FOR t ← son[1], v DO WITH t SELECT FROM symbol => BEGIN IF ctxb[seb[index].idCtx].level = Symbols.lZ AND (LOOPHOLE[seb[index].idValue, Symbols.BitAddress].bd # 0 OR LOOPHOLE[seb[index].idInfo, CARDINAL] MOD WordSize # 0) THEN GO TO fail; GO TO pass; END; subtree => BEGIN subNode ← index; SELECT tb[subNode].name FROM dot, dollar => v ← tb[subNode].son[2]; index, dindex => FOR type ← NormalType[OperandType[tb[subNode].son[1]]], next DO WITH seb[type] SELECT FROM array => IF oldPacked THEN GO TO fail ELSE GO TO pass; arraydesc => next ← UnderType[describedType]; ENDCASE => ERROR; ENDLOOP; seqindex => GO TO fail; uparrow, reloc => GO TO pass; cast, chop => v ← tb[subNode].son[1]; ENDCASE => ERROR; END; ENDCASE => ERROR; REPEAT pass => NULL; fail => Log.ErrorTree[nonAddressable, son[1]]; ENDLOOP; val ← [subtree[index: node]]; IF TestTree[son[1], dot] THEN BEGIN subNode ← GetNode[son[1]]; IF TreeLiteral[tb[subNode].son[1]] THEN WITH tb[subNode].son[2] SELECT FROM symbol => BEGIN val ← MakeStructuredLiteral[ TreeLiteralValue[tb[subNode].son[1]] + LOOPHOLE[seb[index].idValue, Symbols.BitAddress].wd, info]; FreeNode[node]; END; ENDCASE => ERROR; END; VPop[]; VPush[0, unsigned, nRegs]; RETURN END; END.