-- file Pass4Xa.mesa -- last written by Satterthwaite, July 8, 1983 2:10 pm DIRECTORY Alloc: TYPE USING [Notifier], ComData: TYPE USING [ownSymbols, switches, typeINT, typeCARDINAL, typeCHAR, zone], Environment: TYPE USING [bitsPerByte, bitsPerWord, maxCARDINAL, maxINTEGER], Inline: TYPE USING [BITAND, BITOR, BITSHIFT], Literals: TYPE USING [Base, LitDescriptor, ltType], LiteralOps: TYPE USING [FindDescriptor, MasterString], Log: TYPE USING [Error, ErrorN, ErrorTree], P4: TYPE USING [ Attr, voidAttr, ConsState, Covering, Prop, emptyProp, voidProp, Repr, none, signed, unsigned, both, other, OpWordCount, RegCount, maxRegs, WordSeq, ValueDescriptor, checked, AdjustBias, BiasForType, BitsForType, CatchNest, CommonProp, ComputeIndexRegs, Exp, ForceType, MakeStructuredLiteral, MakeTreeLiteral, MaxCardinality, NeutralExp, OperandType, RegsForType, RepForType, RValue, StructuredLiteral, Subst, TreeLiteral, TreeLiteralDesc, TreeLiteralValue, TypeExp, TypeForTree, VAttr, VBias, VPop, VProp, VPush, VRegs, VRep, WordsForType, ZeroP], Pass4: TYPE USING [implicitAttr, implicitBias, implicitType], Symbols: TYPE USING [ Base, BitAddress, WordCount, Type, ISEIndex, CSEIndex, ArraySEIndex, RecordSEIndex, ISENull, RecordSENull, typeANY, ctxType, seType], SymbolOps: TYPE USING [ ArgRecord, BitsPerElement, Cardinality, FirstVisibleSe, FnField, NextSe, RCType, RecordRoot, UnderType, VariantField], Tree: TYPE USING [Base, Index, Link, Map, Scan, Null, treeType], TreeOps: TYPE USING [ FreeNode, FreeTree, GetNode, ListLength, NthSon, OpName, PopTree, PushTree, PushLit, PushNode, ScanList, SetAttr, SetInfo, UpdateList], Types: TYPE USING [Assignable]; Pass4Xa: PROGRAM IMPORTS Inline, Log, LiteralOps, P4, SymbolOps, TreeOps, Types, dataPtr: ComData, passPtr: Pass4 EXPORTS P4 = { OPEN SymbolOps, TreeOps, P4; -- pervasive definitions from Symbols Type: TYPE = Symbols.Type; ISEIndex: TYPE = Symbols.ISEIndex; CSEIndex: TYPE = Symbols.CSEIndex; RecordSEIndex: TYPE = Symbols.RecordSEIndex; BitAddress: TYPE = Symbols.BitAddress; tb: Tree.Base; -- tree base address (local copy) ltb: Literals.Base; -- literal base address (local copy) seb: Symbols.Base; -- se table base address (local copy) ctxb: Symbols.Base; -- context table base address (local copy) ExpANotify: PUBLIC Alloc.Notifier = { -- called by allocator whenever table area is repacked tb ← base[Tree.treeType]; ltb ← base[Literals.ltType]; seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]}; -- expression list manipulation FieldRhs: PROC [t: Tree.Link, type: CSEIndex, cs: ConsState] RETURNS [Tree.Link] = { v: Tree.Link = Rhs[t, type, cs]; RETURN [Safen[v, VProp[], cs, type]]}; ConsOp: PROC [t: Tree.Link] RETURNS [BOOL] = { RETURN [SELECT OpName[t] FROM construct, union, rowcons, all => TRUE, cast, pad => ConsOp[NthSon[t, 1]], ENDCASE => FALSE]}; Safen: PROC [t: Tree.Link, prop: Prop, cs: ConsState, type: CSEIndex] RETURNS [Tree.Link] = { PushTree[t]; IF ~prop.noXfer OR (~prop.noAssign AND RCType[type] # none) OR (cs=$rest AND ~prop.noSelect AND ~prop.immutable) THEN IF ~ConsOp[t] THEN { PushNode[safen, 1]; SetInfo[type]; SetAttr[1, cs=$rest]; SetAttr[2, ~prop.noXfer]}; RETURN [PopTree[]]}; MakeRecord: PROC [record: RecordSEIndex, expList: Tree.Link, cs: ConsState] RETURNS [val: Tree.Link] = { sei: ISEIndex; const: BOOL ← TRUE; prop: Prop ← voidProp; nRegs: RegCount ← 0; EvaluateField: Tree.Map = { type: CSEIndex = UnderType[seb[sei].idType]; IF t = Tree.Null THEN { v ← Tree.Null; IF BitsForType[type] # 0 OR VariantType[type] THEN const ← FALSE} ELSE { v ← FieldRhs[t, type, cs]; 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; prop ← CommonProp[VProp[], prop]; nRegs ← MAX[VRegs[], nRegs]; VPop[]; IF cs = $first THEN cs ← $rest}; sei ← NextSe[sei]; RETURN}; sei ← FirstVisibleSe[seb[record].fieldCtx]; val ← UpdateList[expList, EvaluateField]; IF OpName[val] = list THEN { subNode: Tree.Index = GetNode[val]; tb[subNode].attr1 ← const}; VPush[BiasForType[record], [prop: prop, rep: other], nRegs]; RETURN}; VariantType: PROC [type: CSEIndex] RETURNS [BOOL] = INLINE { RETURN [SELECT seb[type].typeTag FROM union, sequence => TRUE, ENDCASE => FALSE]}; MakeArgRecord: PUBLIC PROC [record: RecordSEIndex, expList: Tree.Link] RETURNS [val: Tree.Link] = { SELECT TRUE FROM (expList = Tree.Null) => {val ← Tree.Null; VPush[0, voidAttr, 0]}; (record = Symbols.RecordSENull) => {val ← FreeTree[expList]; VPush[0, voidAttr, 0]}; (OpName[expList] = list) => val ← MakeRecord[record, expList, $init]; ENDCASE => { type: CSEIndex = UnderType[seb[FirstVisibleSe[seb[record].fieldCtx]].idType]; val ← FieldRhs[expList, type, $init]}; RETURN}; -- construction of packed values (machine dependent) WordLength: CARDINAL = Environment.bitsPerWord; ByteLength: CARDINAL = Environment.bitsPerByte; FillMultiWord: PUBLIC PROC [words: ValueDescriptor, origin: CARDINAL, t: Tree.Link] = { desc: Literals.LitDescriptor = TreeLiteralDesc[t]; IF origin + desc.length <= words.length THEN FOR i: CARDINAL IN [0 .. desc.length) DO words[origin+i] ← ltb[desc.offset][i] ENDLOOP}; PackRecord: PROC [record: RecordSEIndex, expList: Tree.Link] RETURNS [Tree.Link] = { n: CARDINAL = WordsForType[record]; root, type: RecordSEIndex; list: Tree.Link; sei: ISEIndex; offset: CARDINAL; words: ValueDescriptor; more: BOOL; StoreBits: PROC [sei: ISEIndex, value: WORD] = { OPEN Inline; 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 {address ← seb[sei].idValue; size ← seb[sei].idInfo}; w ← address.wd; shift ← (WordLength-offset) - (address.bd+size); words[w] ← BITOR[words[w], BITSHIFT[BITAND[value, Masks[size]], shift]]}; PackField: Tree.Scan = { node: Tree.Index; address: BitAddress; typeId: ISEIndex; subType: CSEIndex; SELECT TRUE FROM t = Tree.Null => NULL; TreeLiteral[t] => StoreBits[sei, TreeLiteralValue[t]]; ENDCASE => { node ← GetNode[t]; SELECT tb[node].name FROM mwconst => { address ← IF seb[root].argument THEN FnField[sei].offset ELSE seb[sei].idValue; FillMultiWord[words, address.wd, tb[node].son[1]]}; union => { typeId ← NARROW[tb[node].son[1], Tree.Link.symbol].index; 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}; ENDCASE => ERROR}; sei ← NextSe[sei]}; words ← (dataPtr.zone).NEW[WordSeq[n]]; FOR i: CARDINAL 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[DESCRIPTOR[words]]]; PushNode[IF n=1 THEN cast ELSE mwconst, 1]; SetInfo[record]; (dataPtr.zone).FREE[@words]; RETURN [PopTree[]]}; PadRecord: PUBLIC PROC [t: Tree.Link, lType: CSEIndex] RETURNS [Tree.Link] = { IF StructuredLiteral[t] THEN { nW: CARDINAL = WordsForType[lType]; words: ValueDescriptor; node: Tree.Index; words ← (dataPtr.zone).NEW[WordSeq[nW]]; FOR w: CARDINAL IN [0 .. nW) DO words[w] ← 0 ENDLOOP; IF TreeLiteral[t] THEN words[0] ← TreeLiteralValue[t] ELSE { node ← GetNode[t]; SELECT tb[node].name FROM mwconst => FillMultiWord[words, 0, tb[node].son[1]]; ENDCASE => ERROR; FreeNode[node]}; PushLit[LiteralOps.FindDescriptor[DESCRIPTOR[words]]]; PushNode[mwconst, 1]; (dataPtr.zone).FREE[@words]} ELSE {PushTree[t]; PushNode[pad, 1]}; SetInfo[lType]; RETURN [PopTree[]]}; ExtractValue: PROC [t: Tree.Link, addr: BitAddress, size: CARDINAL, type: CSEIndex] RETURNS [val: Tree.Link] = { words: ValueDescriptor; desc: Literals.LitDescriptor = TreeLiteralDesc[t]; n: CARDINAL = size/WordLength; IF n > 1 THEN { IF addr.bd # 0 THEN Log.Error[unimplemented]; words ← (dataPtr.zone).NEW[WordSeq[n]]; FOR i: CARDINAL IN [0..n) DO words[i] ← ltb[desc.offset][addr.wd+i] ENDLOOP; PushLit[LiteralOps.FindDescriptor[DESCRIPTOR[words]]]; PushNode[mwconst, 1]; SetInfo[type]; (dataPtr.zone).FREE[@words]; val ← PopTree[]} ELSE val ← MakeStructuredLiteral[ Inline.BITSHIFT[ Inline.BITSHIFT[ltb[desc.offset][addr.wd], addr.bd], -(WordLength - size)], type]; RETURN}; UnpackField: PROC [t: Tree.Link, field: ISEIndex] RETURNS [val: Tree.Link] = { 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]]}; UnpackElement: PROC [t: Tree.Link, i: CARDINAL] RETURNS [val: Tree.Link] = { aType: CSEIndex = OperandType[t]; cType: CSEIndex; addr: BitAddress; nB, nW: CARDINAL; WITH a: seb[aType] SELECT FROM array => { cType ← UnderType[a.componentType]; nB ← BitsPerElement[cType, a.packed]; IF nB > ByteLength THEN { nW ← (nB+(WordLength-1))/WordLength; addr ← [wd:i*nW, bd:0]; nB ← nW*WordLength} ELSE { itemsPerWord: CARDINAL = WordLength/nB; offset: CARDINAL = IF WordsForType[aType] = 1 THEN WordLength - CARDINAL[BitsForType[aType]] ELSE 0; addr ← [wd: i/itemsPerWord, bd: offset + (i MOD itemsPerWord)*nB]}}; ENDCASE => ERROR; RETURN [ExtractValue[t, addr, nB, cType]]}; -- operators Substx: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { type: CSEIndex = tb[node].info; IF OpName[tb[node].son[2]] = result THEN { saveChecked: BOOL = checked; subNode: Tree.Index = GetNode[tb[node].son[2]]; IF ~tb[node].attr3 THEN checked ← tb[node].attr1; tb[node].son[1] ← NeutralExp[tb[node].son[1]]; SELECT ListLength[tb[subNode].son[1]] FROM 0 => ERROR; 1 => val ← --IF tb[subNode].attr3 --THEN tb[subNode].son[1] --ELSE-- ForceType[tb[subNode].son[1], type]; ENDCASE => { PushTree[Tree.Null]; PushTree[tb[subNode].son[1]]; PushNode[construct, 2]; SetInfo[type]; val ← PopTree[]}; tb[subNode].son[1] ← Tree.Null; FreeNode[node]; val ← Rhs[val, type, $init]; checked ← saveChecked} ELSE { val ← Subst[node]; VPush[BiasForType[type], [prop: emptyProp, rep: RepForType[type]], maxRegs]}; RETURN}; Call: PUBLIC PROC [node: Tree.Index] RETURNS [Tree.Link] = { OPEN tb[node]; type: CSEIndex; prop: Prop; son[1] ← Exp[son[1], none]; prop ← VProp[]; VPop[]; type ← OperandType[son[1]]; WITH t: seb[type] SELECT FROM transfer => { IF attr1 AND name # xerror AND t.typeIn # Symbols.RecordSENull THEN son[2] ← Rhs[son[2], t.typeIn, $init] ELSE son[2] ← MakeArgRecord[ArgRecord[t.typeIn], son[2]]; prop ← CommonProp[prop, VProp[]]; VPop[]; prop.noXfer ← prop.noAssign ← prop.noFreeVar ← FALSE; IF nSons > 2 THEN CatchNest[son[3]]; VPush[BiasForType[t.typeOut], [prop: prop, rep: RepForType[t.typeOut]], maxRegs]}; ENDCASE => ERROR; RETURN [[subtree[index: node]]]}; Construct: PUBLIC PROC [node: Tree.Index, cs: ConsState] RETURNS [val: Tree.Link] = { OPEN tb[node]; type: RecordSEIndex = info; record: RecordSEIndex = RecordRoot[type]; prop: Prop; nRegs: RegCount; k: RegCount = RegsForType[type]; SELECT TRUE FROM (OpName[son[2]] = list) => { subNode: Tree.Index; son[2] ← MakeRecord[record, son[2], cs]; nRegs ← VRegs[]; prop ← VProp[]; subNode ← GetNode[son[2]]; IF ~tb[subNode].attr1 THEN { -- ~all fields constant tb[node].attr3 ← tb[subNode].attr3; val ← [subtree[index: node]]; nRegs ← MAX[nRegs, k]} ELSE {val ← PackRecord[type, son[2]]; FreeNode[node]; nRegs ← k}; VPop[]; VPush[0, [prop: prop, rep: other], nRegs]}; (son[2] = Tree.Null) => { val ← Tree.Null; VPush[0, [prop: voidProp, rep: other], k]}; (OpName[son[2]] = union) => { son[2] ← Union[GetNode[son[2]], cs]; IF OpName[son[2]] = union THEN { subNode: Tree.Index = GetNode[son[2]]; IF tb[subNode].attr1 THEN {val ← PackRecord[type, son[2]]; FreeNode[node]} ELSE val ← [subtree[index: node]]} ELSE {val ← ForceType[son[2], type]; son[2] ← Tree.Null; FreeNode[node]}}; ENDCASE => val ← CastUniList[node, type, cs, record]; RETURN}; Union: PUBLIC PROC [node: Tree.Index, cs: ConsState] RETURNS [val: Tree.Link] = { OPEN tb[node]; vSei: ISEIndex = NARROW[son[1], Tree.Link.symbol].index; type: RecordSEIndex = LOOPHOLE[UnderType[vSei]]; tSei: CSEIndex = UnderType[info]; tagged: BOOL = WITH seb[tSei] SELECT FROM union => controlled, ENDCASE => FALSE; attr: Attr; nRegs: RegCount; attr2 ← tagged; SELECT TRUE FROM (OpName[son[2]] = list OR OpName[son[2]] = union) => { son[2] ← MakeRecord[type, son[2], cs]; nRegs ← VRegs[]; attr ← VAttr[]; attr1 ← WITH son[2] SELECT FROM subtree => tb[index].attr1, ENDCASE => FALSE; val ← [subtree[index: node]]; VPop[]; attr.rep ← other; VPush[0, attr, nRegs]}; (son[2] = Tree.Null) => { attr1 ← TRUE; val ← [subtree[index: node]]; VPush[0, [prop: voidProp, rep: other], 1]}; ENDCASE => IF (~tagged OR seb[vSei].idValue = 0) AND WordsForType[type] = 1 AND ZeroOffset[IF tagged THEN TagSei[tSei] ELSE FirstVisibleSe[seb[type].fieldCtx]] THEN val ← CastUniList[node, tSei, cs, type] ELSE { son[2] ← MakeRecord[type, son[2], cs]; attr ← VAttr[]; attr1 ← StructuredLiteral[son[2]]; val ← [subtree[index: node]]; VPop[]; attr.rep ← other; VPush[0, attr, RegsForType[type]]}; RETURN}; TagSei: PROC [tSei: CSEIndex] RETURNS [ISEIndex] = INLINE { RETURN [WITH seb[tSei] SELECT FROM union => tagSei, ENDCASE => Symbols.ISENull]}; ZeroOffset: PROC [sei: ISEIndex] RETURNS [BOOL] = INLINE { RETURN [sei # Symbols.ISENull AND seb[sei].idValue = BitAddress[0, 0]]}; CastUniList: PROC [node: Tree.Index, type: CSEIndex, cs: ConsState, rType: RecordSEIndex] RETURNS [val: Tree.Link] = { target: CSEIndex = UnderType[seb[FirstVisibleSe[seb[rType].fieldCtx]].idType]; prop: Prop; nRegs: RegCount; val ← ForceType[FieldRhs[tb[node].son[2], target, cs], type]; prop ← VProp[]; nRegs ← VRegs[]; VPop[]; tb[node].son[2] ← Tree.Null; FreeNode[node]; VPush[BiasForType[type], [prop: prop, rep: RepForType[type]], nRegs]; RETURN}; RowConstruct: PUBLIC PROC [node: Tree.Index, cs: ConsState] RETURNS [val: Tree.Link] = { OPEN tb[node]; aType: Symbols.ArraySEIndex = info; cType: CSEIndex = UnderType[seb[aType].componentType]; n: CARDINAL = Cardinality[seb[aType].indexType]; const, strings, lstrings: BOOL; prop: Prop ← voidProp; nRegs: RegCount ← 0; l: CARDINAL; EvalElement: Tree.Map = { IF t = Tree.Null THEN {v ← Tree.Null; const ← strings ← lstrings ← FALSE} ELSE { v ← FieldRhs[t, cType, cs]; 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 index SELECT FROM string => { const ← FALSE; IF LiteralOps.MasterString[sti] = sti THEN lstrings ← FALSE ELSE strings ← FALSE}; ENDCASE; ENDCASE => const ← strings ← lstrings ← FALSE; prop ← CommonProp[VProp[], prop]; nRegs ← MAX[VRegs[], nRegs]; VPop[]; IF cs = $first THEN cs ← $rest}; RETURN}; w, nW: CARDINAL; words: ValueDescriptor; bitsLeft: CARDINAL; bitCount: CARDINAL; PackElement: Tree.Scan = { IF TreeLiteral[t] THEN { bitsLeft ← bitsLeft - bitCount; words[w] ← Inline.BITOR[words[w], Inline.BITSHIFT[TreeLiteralValue[t], bitsLeft]]; IF bitsLeft < bitCount THEN {w ← w+1; bitsLeft ← WordLength}} ELSE { node: Tree.Index = GetNode[t]; SELECT tb[node].name FROM mwconst => { FillMultiWord[words, w, tb[node].son[1]]; w ← w + WordsForType[cType]}; ENDCASE => ERROR}}; 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 { nW ← WordsForType[aType]; words ← (dataPtr.zone).NEW[WordSeq[nW]]; FOR w: CARDINAL IN [0 .. nW) DO words[w] ← 0 ENDLOOP; bitCount ← BitsPerElement[cType, seb[aType].packed]; w ← 0; bitsLeft ← IF nW = 1 THEN CARDINAL[BitsForType[aType]] ELSE WordLength; ScanList[son[2], PackElement]; FreeNode[node]; PushLit[LiteralOps.FindDescriptor[DESCRIPTOR[words]]]; PushNode[IF nW = 1 THEN cast ELSE mwconst, 1]; SetInfo[aType]; (dataPtr.zone).FREE[@words]; val ← PopTree[]; nRegs ← RegsForType[aType]} ELSE { IF (attr1 ← strings # lstrings) THEN prop.noFreeVar ← FALSE; val ← [subtree[index: node]]}; VPush[0, [prop: prop, rep: other], nRegs]; RETURN}; All: PUBLIC PROC [node: Tree.Index, cs: ConsState] RETURNS [val: Tree.Link] = { OPEN tb[node]; aType: Symbols.ArraySEIndex = info; cType: CSEIndex = UnderType[seb[aType].componentType]; prop: Prop; val ← [subtree[index: node]]; IF son[1] = Tree.Null THEN prop ← voidProp ELSE { son[1] ← FieldRhs[son[1], cType, cs]; IF TreeLiteral[son[1]] AND WordsForType[aType] = 1 THEN { nB: CARDINAL = BitsPerElement[cType, seb[aType].packed]; v, w: WORD; v ← TreeLiteralValue[son[1]]; w ← 0; THROUGH [1 .. Cardinality[seb[aType].indexType]] DO w ← Inline.BITOR[Inline.BITSHIFT[w, nB], v] ENDLOOP; val ← ForceType[MakeTreeLiteral[w], aType]; FreeNode[node]} ELSE IF OperandType[son[1]] # cType THEN son[1] ← ForceType[son[1], cType]; prop ← VProp[]; VPop[]}; VPush[0, [prop: prop, rep: other], RegsForType[aType]]; RETURN}; Dot: PUBLIC PROC [node: Tree.Index, target: Repr] RETURNS [Tree.Link] = { OPEN tb[node]; prop: Prop; attr: Attr; bias: INTEGER; nRegs: RegCount; son[1] ← RValue[son[1], 0, unsigned]; prop ← VProp[]; prop.noSelect ← FALSE; nRegs ← MAX[RegsForType[info], VRegs[]]; VPop[]; son[2] ← Exp[son[2], target]; attr ← VAttr[]; bias ← VBias[]; VPop[]; attr.prop ← CommonProp[attr.prop, prop]; attr1 ← ~attr3 AND (checked OR dataPtr.switches['n]); VPush[bias, attr, nRegs]; RETURN [[subtree[index: node]]]}; Dollar: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { OPEN tb[node]; attr: Attr; immutable: BOOL; bias: INTEGER; nRegs: RegCount; k: RegCount = RegsForType[info]; son[1] ← RValue[son[1], BiasForType[OperandType[son[1]]], none]; nRegs ← VRegs[]; attr.prop ← VProp[]; immutable ← attr.prop.immutable; VPop[]; son[2] ← Exp[son[2], none]; attr.rep ← VRep[]; bias ← VBias[]; IF ~StructuredLiteral[son[1]] THEN { val ← [subtree[index: node]]; nRegs ← MAX[nRegs, k]; attr.prop ← CommonProp[attr.prop, VProp[]]; attr.prop.noSelect ← FALSE; attr.prop.immutable ← immutable} ELSE { val ← UnpackField[son[1], NARROW[son[2], Tree.Link.symbol].index]; FreeNode[node]; nRegs ← k}; VPop[]; VPush[bias, attr, nRegs]; RETURN}; Index: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { OPEN tb[node]; iType, cType: CSEIndex; next: Type; prop: Prop; immutable: BOOL; nRegs: RegCount; son[1] ← Exp[son[1], none]; prop ← VProp[]; immutable ← prop.immutable; FOR aType: CSEIndex ← OperandType[son[1]], UnderType[next] DO WITH seb[aType] SELECT FROM array => { iType ← UnderType[indexType]; cType ← UnderType[componentType]; EXIT}; arraydesc => next ← describedType; long => next ← rangeType; ENDCASE => ERROR; ENDLOOP; IF WordsForType[cType] > OpWordCount.LAST THEN Log.ErrorTree[addressOverflow, [subtree[node]]]; IF name = dindex THEN { son[2] ← RValue[son[2], BiasForType[iType], unsigned]; attr1 ← checked OR dataPtr.switches['n]; attr3 ← checked OR dataPtr.switches['b]} ELSE son[2] ← Rhs[son[2], iType, $init, TRUE]; prop ← CommonProp[prop, VProp[]]; SELECT TRUE FROM (TreeLiteral[son[2]] AND OpName[son[1]] = all) => { subNode: Tree.Index = GetNode[son[1]]; val ← tb[subNode].son[1]; tb[subNode].son[1] ← Tree.Null; FreeNode[node]; nRegs ← RegsForType[cType]}; (TreeLiteral[son[2]] AND StructuredLiteral[son[1]]) => { val ← UnpackElement[son[1], TreeLiteralValue[son[2]]]; FreeNode[node]; nRegs ← RegsForType[cType]}; ENDCASE => { val ← [subtree[index:node]]; nRegs ← ComputeIndexRegs[node]; prop.noSelect ← FALSE; prop.immutable ← immutable}; VPop[]; VPop[]; VPush[BiasForType[cType], [prop: prop, rep: RepForType[cType]], nRegs]; RETURN}; SeqIndex: PUBLIC PROC [node: Tree.Index] RETURNS [Tree.Link] = { OPEN tb[node]; iType, cType, sType: CSEIndex; prop: Prop; nRegs: RegCount; son[1] ← Exp[son[1], none]; prop ← VProp[]; sType ← OperandType[son[1]]; WITH t: seb[sType] SELECT FROM sequence => { iType ← UnderType[seb[t.tagSei].idType]; cType ← UnderType[t.componentType]; attr3 ← t.controlled AND (checked OR dataPtr.switches['b])}; array => { iType ← UnderType[t.indexType]; cType ← UnderType[t.componentType]; attr3 ← checked OR dataPtr.switches['b]}; ENDCASE; IF WordsForType[cType] > OpWordCount.LAST THEN Log.ErrorTree[addressOverflow, [subtree[node]]]; son[2] ← RValue[son[2], BiasForType[iType], TargetRep[RepForType[iType]]]; nRegs ← ComputeIndexRegs[node]; prop ← CommonProp[prop, VProp[]]; prop.noSelect ← FALSE; VPop[]; VPop[]; VPush[BiasForType[cType], [prop: prop, rep: RepForType[cType]], nRegs]; RETURN [[subtree[index:node]]]}; Reloc: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { prop: Prop; nRegs: RegCount; type: CSEIndex = tb[node].info; tb[node].son[1] ← RValue[tb[node].son[1], 0, unsigned]; prop ← VProp[]; tb[node].son[2] ← RValue[tb[node].son[2], 0, unsigned]; prop ← CommonProp[prop, VProp[]]; nRegs ← ComputeIndexRegs[node]; VPop[]; VPop[]; IF ~tb[node].attr1 AND ZeroP[tb[node].son[1]] THEN { rType, subType, next: CSEIndex; FOR subType ← OperandType[tb[node].son[2]], next DO -- CanonicalType WITH r: seb[subType] SELECT FROM relative => { rType ← UnderType[r.resultType]; PushTree[tb[node].son[2]]; tb[node].son[2] ← Tree.Null; IF tb[node].attr2 AND seb[UnderType[r.offsetType]].typeTag # long THEN { PushNode[lengthen, 1]; SetAttr[1, FALSE]; SetAttr[2, FALSE]; SetAttr[3, FALSE]} ELSE PushNode[cast, 1]; EXIT}; record => next ← UnderType[seb[FirstVisibleSe[r.fieldCtx]].idType]; ENDCASE => ERROR; ENDLOOP; SetInfo[rType]; PushNode[uparrow, 1]; SetInfo[type]; SetAttr[1, dataPtr.switches['n]]; SetAttr[2, tb[node].attr2]; val ← PopTree[]; FreeNode[node]} ELSE val ← [subtree[node]]; prop.noSelect ← FALSE; VPush[BiasForType[type], [prop: prop, rep: RepForType[type]], nRegs]; RETURN}; Assignment: PUBLIC PROC [node: Tree.Index] RETURNS [Tree.Link] = { OPEN tb[node]; lhsType: CSEIndex; bias: INTEGER; attr: Attr; nRegs: RegCount; son[1] ← Exp[son[1], none]; bias ← VBias[]; attr ← VAttr[]; nRegs ← VRegs[]; lhsType ← OperandType[son[1]]; son[2] ← Rhs[son[2], lhsType, $first]; attr.prop ← CommonProp[attr.prop, VProp[]]; attr.prop.noAssign ← FALSE; VPop[]; VPop[]; VPush[bias, attr, nRegs]; RETURN [RewriteAssign[node, lhsType]]}; Extract: PUBLIC PROC [node: Tree.Index] RETURNS [Tree.Link] = { subNode: Tree.Index = GetNode[tb[node].son[1]]; rType: RecordSEIndex = tb[subNode].info; prop: Prop ← voidProp; sei: ISEIndex; AssignItem: Tree.Map = { type: CSEIndex; saveType: CSEIndex = passPtr.implicitType; saveBias: INTEGER = passPtr.implicitBias; saveAttr: Attr = passPtr.implicitAttr; IF t = Tree.Null THEN v ← Tree.Null ELSE { subNode: Tree.Index = GetNode[t]; type ← UnderType[seb[sei].idType]; passPtr.implicitType ← type; passPtr.implicitBias ← BiasForType[type]; passPtr.implicitAttr.rep ← RepForType[type]; v ← IF tb[subNode].name = extract THEN Extract[subNode] ELSE Assignment[subNode]; prop ← CommonProp[prop, VProp[]]; VPop[]}; sei ← NextSe[sei]; passPtr.implicitAttr ← saveAttr; passPtr.implicitBias ← saveBias; passPtr.implicitType ← saveType; RETURN}; sei ← FirstVisibleSe[seb[rType].fieldCtx]; tb[subNode].son[1] ← UpdateList[tb[subNode].son[1], AssignItem]; tb[node].son[2] ← Exp[tb[node].son[2], none]; prop ← CommonProp[prop, VProp[]]; VPop[]; VPush[BiasForType[rType], [prop: prop, rep: RepForType[rType]], maxRegs]; RETURN [[subtree[index:node]]]}; New: PUBLIC PROC [node: Tree.Index] RETURNS [Tree.Link] = { OPEN tb[node]; prop: Prop ← voidProp; IF son[1] # Tree.Null THEN {son[1] ← Exp[son[1], none]; prop ← VProp[]; VPop[]}; IF OpName[son[2]] = apply THEN { subNode: Tree.Index = GetNode[son[2]]; type: CSEIndex; vSei: ISEIndex; TypeExp[tb[subNode].son[1]]; type ← UnderType[TypeForTree[tb[subNode].son[1]]]; tb[subNode].son[2] ← Rhs[tb[subNode].son[2], dataPtr.typeCARDINAL, $init]; prop ← CommonProp[prop, VProp[]]; VPop[]; vSei ← VariantField[type]; IF vSei # Symbols.ISENull THEN { vType: CSEIndex = UnderType[seb[vSei].idType]; subType: CSEIndex = OperandType[tb[subNode].son[2]]; n: LONG CARDINAL = WITH t: seb[vType] SELECT FROM sequence => MIN[ Cardinality[seb[t.tagSei].idType], MaxCardinality[t.componentType, t.packed, OpWordCount.LAST-WordsForType[type]]] ENDCASE => 0; IF subType = dataPtr.typeINT OR ~(Cardinality[subType] IN [1..n]) THEN -- (0..n] tb[subNode].son[2] ← CheckRange[tb[subNode].son[2], n, dataPtr.typeCARDINAL]}} ELSE { TypeExp[son[2], OpName[son[3]] = body]; IF WordsForType[UnderType[TypeForTree[son[2]]]] > OpWordCount.LAST THEN Log.ErrorTree[unimplemented, [subtree[node]]]}; SELECT OpName[son[3]] FROM body => { expNode: Tree.Index = GetNode[son[3]]; PushNode[body, 0]; SetInfo[tb[expNode].info]; son[3] ← PopTree[]}; signalinit => NULL; ENDCASE => IF son[3] # Tree.Null THEN { type: CSEIndex = UnderType[TypeForTree[son[2]]]; subProp: Prop; son[3] ← Rhs[son[3], type, $init]; subProp ← VProp[]; VPop[]; IF attr3 THEN son[3] ← Safen[son[3], subProp, $init, type]; prop ← CommonProp[prop, subProp]}; IF nSons > 3 THEN CatchNest[son[4]]; prop.noXfer ← prop.noFreeVar ← FALSE; VPush[0, [prop: prop, rep: unsigned], maxRegs]; RETURN [[subtree[index:node]]]}; Narrow: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { type: CSEIndex = tb[node].info; IF tb[node].son[2] # Tree.Null THEN TypeExp[tb[node].son[2]]; IF tb[node].attr2 OR tb[node].attr3 THEN { OPEN tb[node]; prop: Prop; son[1] ← RValue[son[1], 0, RepForType[OperandType[son[1]]]]; prop ← VProp[]; prop.noXfer ← FALSE; VPop[]; IF nSons > 2 THEN CatchNest[son[3]]; val ← [subtree[index: node]]; VPush[BiasForType[type], [prop: prop, rep: RepForType[type]], maxRegs]} ELSE { val ← Rhs[tb[node].son[1], type, $init]; tb[node].son[1] ← Tree.Null; FreeNode[node]}}; TargetRep: --PUBLIC-- PROC [rep: Repr] RETURNS [Repr] = INLINE { RETURN [--IF rep = both THEN signed ELSE-- rep]}; Rhs: PUBLIC PROC [exp: Tree.Link, lType: CSEIndex, cs: ConsState, voidOK: BOOL←FALSE] RETURNS [val: Tree.Link] = { lBias: INTEGER = BiasForType[lType]; lRep: Repr = RepForType[lType]; nw: Symbols.WordCount = WordsForType[lType]; rType: CSEIndex = OperandType[exp]; rRep: Repr; WITH exp SELECT FROM subtree => { node: Tree.Index = index; val ← SELECT tb[node].name FROM construct => Construct[node, cs], union => Union[node, cs], rowcons => RowConstruct[node, cs], all => All[node, cs], ENDCASE => RValue[exp, lBias, TargetRep[lRep]]}; ENDCASE => val ← RValue[exp, lBias, TargetRep[lRep]]; rRep ← VRep[]; IF ~Types.Assignable[[dataPtr.ownSymbols, lType], [dataPtr.ownSymbols, rType]] THEN Log.ErrorTree[typeClash, val]; IF ~(IF nw = 0 THEN voidOK ELSE WordsForType[rType] = nw) THEN SELECT TRUE FROM (seb[lType].typeTag = record) AND (seb[rType].typeTag = record) => val ← PadRecord[val, lType]; (seb[lType].typeTag = union) AND (seb[rType].typeTag = union) => NULL; ENDCASE => Log.ErrorTree[sizeClash, val]; IF nw > OpWordCount.LAST THEN Log.ErrorTree[unimplemented, val]; IF (lType = dataPtr.typeINT AND rRep = unsigned) OR ((rType = dataPtr.typeINT AND rRep = signed) AND lRep = unsigned) THEN val ← CheckRange[val, CARDINAL[Environment.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.typeCHAR AND (rRep # both OR TreeLiteral[val]) THEN val ← CheckRange[val, Cardinality[lType], lType]; long => IF (lRep=signed AND rRep=unsigned) OR (lRep=unsigned AND rRep=signed) THEN val ← CheckRange[val, CARDINAL[Environment.maxINTEGER]+1, lType]; ENDCASE => NULL; RETURN}; Cover: PUBLIC PROC [lType: CSEIndex, lRep: Repr, rType: CSEIndex, rRep: Repr] RETURNS [Covering] = { 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]}; Bounds: PROC [type: CSEIndex, rep: Repr] RETURNS [lb, ub: LONG INTEGER] = { WITH t: seb[type] SELECT FROM subrange => {lb ← t.origin; ub ← lb + t.range}; enumerated => {lb ← 0; ub ← t.nValues-1}; relative => [lb, ub] ← Bounds[UnderType[t.offsetType], rep]; ENDCASE => SELECT rep FROM signed => {lb ← -Environment.maxINTEGER-1; ub ← Environment.maxINTEGER}; both => {lb ← 0; ub ← Environment.maxINTEGER}; ENDCASE => {lb ← 0; ub ← Environment.maxCARDINAL}; RETURN}; CheckRange: PUBLIC PROC [t: Tree.Link, bound: CARDINAL, type: CSEIndex] RETURNS [val: Tree.Link] = { SELECT TRUE FROM (bound = 0) => val ← t; TreeLiteral[t] => val ← IF TreeLiteralValue[t] >= bound THEN BoundsFault[t,type] ELSE t; (checked OR dataPtr.switches['b]) AND ~Bounded[t, bound] => { PushTree[MakeTreeLiteral[bound]]; PushTree[t]; PushNode[check,-2]; SetInfo[type]; val ← PopTree[]}; ENDCASE => val ← t; RETURN}; Bounded: PROC [t: Tree.Link, bound: CARDINAL] RETURNS [BOOL] = INLINE { IF OpName[t] = mod THEN { t2: Tree.Link = NthSon[t, 2]; RETURN [TreeLiteral[t2] AND TreeLiteralValue[t2] IN [0..bound]]} ELSE RETURN [FALSE]}; BoundsFault: PROC [t: Tree.Link, type: CSEIndex] RETURNS [Tree.Link] = { Log.ErrorTree[boundsFault, AdjustBias[t, -BiasForType[type]]]; PushTree[t]; -- PushTree[MakeTreeLiteral[0]]; PushNode[check, 2]; SetInfo[type]; RETURN [PopTree[]]}; RewriteAssign: PUBLIC PROC [node: Tree.Index, lType: CSEIndex] RETURNS [Tree.Link] = { IF seb[lType].typeTag = union THEN { WITH tb[node].son[1] SELECT FROM subtree => { subType: CSEIndex; subNode: Tree.Index = index; SELECT tb[subNode].name FROM dot => { subType ← OperandType[tb[subNode].son[1]]; PushTree[tb[subNode].son[1]]; PushNode[uparrow, 1]; SetInfo[WITH seb[subType] SELECT FROM ref => UnderType[refType], ENDCASE => Symbols.typeANY]; tb[subNode].son[1] ← PopTree[]; tb[subNode].name ← dollar}; dollar => NULL; ENDCASE => NULL}; -- flagged by code generators for now ENDCASE => NULL}; -- flagged by code generators for now IF tb[node].name = assignx THEN tb[node].info ← OperandType[tb[node].son[1]]; RETURN [[subtree[index: node]]]}; }.