DIRECTORY
Alloc: TYPE USING [Notifier],
ComData: 
TYPE 
USING [
interface, typeCARDINAL, typeINT, typeStringBody],
 
LiteralOps: TYPE USING [FindDescriptor],
Log: TYPE USING [Error, ErrorTree, WarningTree],
P4: 
TYPE 
USING [
Attr, voidAttr, Prop, Repr, none, unsigned, both, other, RegCount, maxRegs,
WordSeq, ValueDescriptor,
BiasForType, BitsForType, CatchNest, CommonAttr, CommonProp, Exp,
FillMultiWord, ForceType, LiteralAttr, MakeArgRecord, MakeStructuredLiteral,
MakeTreeLiteral, OperandType, RegsForType, RelTest, RepForType,
Rhs, RValue, StructuredLiteral, TreeLiteral, TreeLiteralValue, TypeExp,
TypeForTree, VAttr, VPop, VProp, VPush, VRegs, VRep, WordsForType],
 
Symbols: 
TYPE 
USING [
Base, BitAddress, BitCount, ByteLength, WordLength,
ISEIndex, CSEIndex, ISENull, codeCHAR, codeINT, lZ,
ctxType, seType],
 
SymbolOps: 
TYPE 
USING [
ArgRecord, BitsPerElement, Cardinality, FirstCtxSe, NormalType, NextSe,
PackedSize, VariantField, UnderType],
 
SymLiteralOps: TYPE USING [TypeRef],
Tree: TYPE USING [Base, Index, Link, NodeName, Null, treeType],
TreeOps: 
TYPE 
USING [
FreeNode, FreeTree, GetNode, IdentityMap, MakeNode, OpName, PopTree,
PushLit, PushNode, PushSe, PushTree, SetAttr, SetInfo];
 
 
Pass4Xc: 
PROGRAM
IMPORTS
Log, LiteralOps, P4, SymbolOps, SymLiteralOps, TreeOps,
dataPtr: ComData
 
EXPORTS P4 = {
OPEN SymbolOps, TreeOps, P4;
CSEIndex: TYPE = Symbols.CSEIndex;
WordLength: CARDINAL = Symbols.WordLength;
tb: Tree.Base; -- tree base address (local copy)
seb: Symbols.Base; -- se table base address (local copy)
ctxb: Symbols.Base; -- context table base address (local copy)
ExpCNotify: 
PUBLIC Alloc.Notifier = {
called by allocator whenever table area is repacked
tb ← base[Tree.treeType];
seb ← base[Symbols.seType];  ctxb ← base[Symbols.ctxType]};
 
interval utilities
NormalizeRange: 
PUBLIC 
PROC [t: Tree.Link] 
RETURNS [val: Tree.Link] = {
next: Tree.Link;
FOR val ← t, next 
DO
WITH val 
SELECT 
FROM
symbol => {
lBound: INTEGER = BiasForType[UnderType[index]];
THROUGH [1..2] 
DO
PushTree[MakeTreeLiteral[ABS[lBound]]];
IF lBound < 0 THEN PushNode[uminus, 1];
ENDLOOP;
 
PushTree[MakeTreeLiteral[Cardinality[index] - 1]];
PushNode[plus, 2];  SetInfo[dataPtr.typeINT];
next ← MakeNode[intCC, 2]};
 
subtree => {
node: Tree.Index = index;
SELECT tb[node].name 
FROM
subrangeTC, cdot => {
next ← tb[node].son[2]; tb[node].son[2] ← Tree.Null; FreeNode[node]};
 
IN [intOO .. intCC] => EXIT;
ENDCASE => ERROR};
 
 
ENDCASE => ERROR;
 
ENDLOOP;
 
RETURN};
 
Interval: 
PUBLIC 
PROC [node: Tree.Index, bias: 
INTEGER, target: Repr]
RETURNS [const: BOOL] = {
OPEN tb[node];
attr: Attr;
nRegs: RegCount;
son[1] ← RValue[son[1], bias, target];
attr ← VAttr[]; nRegs ← VRegs[];
son[2] ← RValue[son[2], bias, target];
nRegs ← MAX[VRegs[], nRegs];  attr ← CommonAttr[attr, VAttr[]];
VPop[];  VPop[];  VPush[bias, attr, nRegs];
const ← StructuredLiteral[son[1]] AND StructuredLiteral[son[2]] AND ~attr1;
RETURN};
 
EmptyInterval: PUBLIC SIGNAL = CODE;
ConstantInterval: 
PUBLIC 
PROC [node: Tree.Index] 
RETURNS [origin, range: 
INTEGER] = {
OPEN tb[node];
uBound: INTEGER;
rep: Repr ← VRep[];
empty: BOOL ← FALSE;
origin ← TreeLiteralValue[son[1]];  uBound ← TreeLiteralValue[son[2]];
SELECT name 
FROM
intOO, intOC => {
IF RelTest[son[1], son[2], relGE, rep] THEN empty ← TRUE;
origin ← origin + 1;
son[1] ← FreeTree[son[1]];
name ← IF name = intOO THEN intCO ELSE intCC;
son[1] ← MakeTreeLiteral[origin]};
 
ENDCASE;
 
SELECT name 
FROM
intCC => IF RelTest[son[1], son[2], relG, rep] THEN empty ← TRUE;
intCO => {
IF RelTest[son[1], son[2], relGE, rep] THEN empty ← TRUE;
uBound ← uBound - 1;
son[2] ← FreeTree[son[2]];
name ← intCC;  son[2] ← MakeTreeLiteral[uBound]};
 
ENDCASE => ERROR;
 
IF ~empty THEN range ← uBound - origin ELSE {SIGNAL EmptyInterval; range ← 0};
RETURN};
 
 
type utilities (move?)
operators on types
TypeOp: 
PUBLIC 
PROC [node: Tree.Index] 
RETURNS [val: Tree.Link] = {
SELECT tb[node].name FROM
size => val ← Size[node];
first, last => val ← EndPoint[node];
typecode => val ← TypeCode[node];
ENDCASE => {
Log.Error[unimplemented]; VPush[0, voidAttr, 0]; val ← [subtree[node]]};
 
 
RETURN};
 
Size: 
PROC [node: Tree.Index] 
RETURNS [val: Tree.Link] = {
type: CSEIndex;
ApplyLit: 
PROC [op: Tree.NodeName, val: 
WORD] = {
PushTree[MakeTreeLiteral[val]];  PushNode[op, 2];
SetInfo[dataPtr.typeINT];  SetAttr[1, FALSE];  SetAttr[2, FALSE]};
 
IF OpName[tb[node].son[1]] = apply 
THEN {
subNode: Tree.Index = GetNode[tb[node].son[1]];
sei: Symbols.ISEIndex;
bitsPerItem: Symbols.BitCount;
TypeExp[tb[subNode].son[1]];  type ← UnderType[TypeForTree[tb[subNode].son[1]]];
SELECT 
TRUE 
FROM
(type = dataPtr.typeStringBody) => bitsPerItem ← Symbols.ByteLength;
((sei ← VariantField[type]) # Symbols.ISENull) => {
subType: CSEIndex = UnderType[seb[sei].idType];
bitsPerItem ← 
WITH t: seb[subType] 
SELECT 
FROM
sequence => BitsPerElement[t.componentType, t.packed],
ENDCASE => ERROR};
 
 
ENDCASE => ERROR;
 
PushTree[tb[subNode].son[2]];  tb[subNode].son[2] ← Tree.Null;
IF bitsPerItem < WordLength 
THEN {
itemsPerWord: CARDINAL = WordLength/CARDINAL[bitsPerItem];
ApplyLit[plus, itemsPerWord-1];  ApplyLit[div, itemsPerWord]}
 
ELSE ApplyLit[times, bitsPerItem/WordLength];
ApplyLit[plus, P4.WordsForType[type]];
IF tb[node].son[2] # Tree.Null 
THEN {
PushTree[tb[node].son[2]];  tb[node].son[2] ← Tree.Null;
PushNode[times, 2]; 
SetInfo[dataPtr.typeINT];  SetAttr[1, FALSE];  SetAttr[2, FALSE]}}
 
 
ELSE {
TypeExp[tb[node].son[1]];  type ← UnderType[TypeForTree[tb[node].son[1]]];
IF tb[node].son[2] = Tree.Null THEN PushTree[MakeTreeLiteral[P4.WordsForType[type]]]
ELSE {
nBits: CARDINAL = P4.BitsForType[type];
PushTree[tb[node].son[2]];  tb[node].son[2] ← Tree.Null;
IF nBits <= Symbols.ByteLength 
THEN {
n: CARDINAL = WordLength/PackedSize[nBits];
ApplyLit[plus, n-1];  ApplyLit[div, n]}
 
ELSE  ApplyLit[times, P4.WordsForType[type]]}};
 
 
val ← Rhs[PopTree[], dataPtr.typeCARDINAL];  FreeNode[node]};
 
EndPoint: 
PROC [node: Tree.Index] 
RETURNS [val: Tree.Link] = {
OPEN tb[node];
type, next: CSEIndex;
first: BOOL = (name=first);
MaxInteger: WORD = INTEGER.LAST;
MaxWord: WORD = CARDINAL.LAST;
v: WORD;
vv: ARRAY [0..2) OF WORD;
TypeExp[son[1]];
FOR type ← UnderType[TypeForTree[son[1]]], next 
DO
WITH seb[type] 
SELECT 
FROM
basic => {
v ← 
SELECT code 
FROM
Symbols.codeINT => IF first THEN MaxInteger+1 ELSE MaxInteger,
Symbols.codeCHAR => IF first THEN 0 ELSE CARDINAL[Cardinality[type]-1],
ENDCASE => IF first THEN 0 ELSE MaxWord;
 
GO TO short};
 
enumerated => {
v ← IF first THEN 0 ELSE CARDINAL[Cardinality[type]-1]; GO TO short};
 
relative => next ← UnderType[offsetType];
subrange => {v ← IF first THEN origin ELSE origin+range; GO TO short};
long => {
vv ← 
IF UnderType[rangeType] = dataPtr.typeINT
THEN IF first THEN [0, MaxInteger+1] ELSE [MaxWord, MaxInteger]
ELSE IF first THEN [0, 0] ELSE [MaxWord, MaxWord];
 
GO TO long};
 
ENDCASE => ERROR;
 
REPEAT
short => val ← MakeTreeLiteral[v];
long => {
PushLit[LiteralOps.FindDescriptor[DESCRIPTOR[vv]]];
PushNode[mwconst, 1];  SetInfo[type];  val ← PopTree[]};
 
 
ENDLOOP;
 
FreeNode[node];
VPush[0, LiteralAttr[RepForType[type]], RegsForType[type]]; RETURN};
 
TypeCode: 
PROC [node: Tree.Index] 
RETURNS [val: Tree.Link] = {
TypeExp[tb[node].son[1]];
IF dataPtr.interface 
THEN val ← [subtree[index: node]]
ELSE {
val ← SymLiteralOps.TypeRef[TypeForTree[tb[node].son[1]], FALSE];
FreeNode[node]};
 
 
VPush[0, LiteralAttr[both], 1];  RETURN};
 
 
misc transfer operators
MiscXfer: 
PUBLIC 
PROC [node: Tree.Index] 
RETURNS [Tree.Link] = {
type: CSEIndex;
attr: Attr;
SELECT tb[node].name FROM
create => {
tb[node].son[1] ← RValue[tb[node].son[1], 0, none];
attr ← [prop: VProp[], rep: unsigned];  VPop[]};
 
fork => {
OPEN tb[node];
son[1] ← Exp[son[1], none];
attr.prop ← VProp[]; VPop[];  type ← OperandType[son[1]];
WITH t: seb[type] 
SELECT 
FROM
transfer => {
son[2] ← MakeArgRecord[ArgRecord[t.typeIn], son[2]];
attr.prop ← CommonProp[attr.prop, VProp[]]; attr.rep ← other;  VPop[]};
 
ENDCASE => ERROR};
 
 
ENDCASE => {Log.Error[unimplemented]; attr ← voidAttr};
 
attr.prop.noXfer ← attr.prop.noFreeVar ← FALSE;  VPush[0, attr, maxRegs];
IF tb[node].nSons > 2 THEN CatchNest[tb[node].son[3]];
RETURN [[subtree[index: node]]]};
 
 
NIL
Nil: 
PUBLIC 
PROC [node: Tree.Index] 
RETURNS [Tree.Link] = {
type: CSEIndex = tb[node].info;
n: CARDINAL;
words: ValueDescriptor;
IF tb[node].son[1] # Tree.Null THEN TypeExp[tb[node].son[1]];
n ← P4.WordsForType[type];
words ← NEW[WordSeq[n]];
FOR i: CARDINAL IN [0..n) DO words[i] ← 0 ENDLOOP;
PushLit[LiteralOps.FindDescriptor[DESCRIPTOR[@words[0], n]]];
IF n > 1 THEN {PushNode[mwconst, 1]; SetInfo[type]};
FreeNode[node];  words ← NIL;
VPush[BiasForType[type], LiteralAttr[RepForType[type]], RegsForType[type]];
RETURN [ForceType[PopTree[], type]]};
 
 
misc addressing operators
AddrOp: 
PUBLIC 
PROC [node: Tree.Index] 
RETURNS [val: Tree.Link] = {
attr: Attr;
nRegs: RegCount;
SELECT tb[node].name FROM
addr => val ← Addr[node];
base => {
tb[node].son[1] ← Exp[tb[node].son[1], none];
nRegs ← VRegs[]; attr ← [prop: VProp[], rep: unsigned];  VPop[];
VPush[0, attr, nRegs];  val ← [subtree[index: node]]};
 
length => {
type: CSEIndex;
tb[node].son[1] ← Exp[tb[node].son[1], none];
type ← OperandType[tb[node].son[1]];
WITH seb[type] 
SELECT 
FROM
array => {
val ← MakeTreeLiteral[Cardinality[indexType]];
FreeNode[node];  attr ← LiteralAttr[both];  nRegs ← 1};
 
ENDCASE => {
val ← [subtree[index: node]]; attr ← [prop: VProp[], rep: both]; nRegs ← VRegs[]};
 
 
VPop[];  VPush[0, attr, nRegs]};
 
arraydesc =>
val ← IF OpName[tb[node].son[1]] # list THEN Desc[node] ELSE DescList[node];
 
ENDCASE => {
Log.Error[unimplemented]; VPush[0, voidAttr, 0]; val ← [subtree[node]]};
 
 
RETURN};
 
Addr: 
PROC [node: Tree.Index] 
RETURNS [val: Tree.Link] = {
OPEN tb[node];
v: Tree.Link;
subNode: Tree.Index;
type, next: CSEIndex;
prop: Prop;
nRegs: RegCount;
son[1] ← Exp[son[1], none];
nRegs ← MAX[VRegs[], RegsForType[info]];  prop ← VProp[];
FOR t: Tree.Link ← son[1], v 
DO
WITH t 
SELECT 
FROM
symbol => {
sei: Symbols.ISEIndex = index;
IF ctxb[seb[sei].idCtx].level = Symbols.lZ 
AND
(
LOOPHOLE[seb[sei].idValue, Symbols.BitAddress].bd # 0 
OR
LOOPHOLE[seb[sei].idInfo, CARDINAL] MOD WordLength # 0) THEN GO TO fail;
 
 
GO TO pass};
 
subtree => {
subNode ← index;
SELECT tb[subNode].name 
FROM
dot, dollar =>  v ← tb[subNode].son[2];
index, dindex, seqindex =>
FOR  type ← NormalType[OperandType[tb[subNode].son[1]]], next 
DO
WITH t: seb[type] 
SELECT 
FROM
array => IF t.packed THEN GO TO fail ELSE GO TO pass;
sequence => IF t.packed THEN GO TO fail ELSE GO TO pass;
arraydesc => next ← UnderType[t.describedType];
ENDCASE => ERROR;
 
ENDLOOP;
 
 
apply => GO TO fail;
uparrow, reloc => GO TO pass;
cast, chop => v ← tb[subNode].son[1];
ENDCASE => ERROR};
 
 
ENDCASE => ERROR;
 
REPEAT
pass => NULL;
fail => Log.ErrorTree[nonAddressable, son[1]]; 
 
ENDLOOP;
 
val ← [subtree[index: node]];
IF OpName[son[1]] = dot 
THEN {
subNode ← GetNode[son[1]];
IF TreeLiteral[tb[subNode].son[1]] 
THEN {
val ← MakeStructuredLiteral[
TreeLiteralValue[tb[subNode].son[1]] + 
LOOPHOLE[
seb[NARROW[tb[subNode].son[2], Tree.Link.symbol].index].idValue,
Symbols.BitAddress].wd,
 
info];
 
FreeNode[node]}};
 
 
VPop[];
VPush[0, [prop: prop, rep: unsigned], nRegs];  RETURN};
 
Desc: 
PROC [node: Tree.Index] 
RETURNS [Tree.Link] = {
subNode: Tree.Index = GetNode[tb[node].son[1]];
long: BOOL = tb[subNode].attr2;
prop: Prop;
nRegs: RegCount;
subType: CSEIndex;
tb[subNode].son[1] ← Exp[tb[subNode].son[1], none];
nRegs ← VRegs[];  prop ← VProp[];  VPop[];
subType ← OperandType[tb[subNode].son[1]];
WITH t: seb[subType] 
SELECT 
FROM
array => {
n: CARDINAL = Cardinality[t.indexType];
IF n = 0 THEN Log.WarningTree[sizeClash, tb[subNode].son[1]];
IF t.packed 
AND (BitsForType[subType] 
MOD WordLength # 0) 
THEN
Log.ErrorTree[nonAddressable, tb[subNode].son[1]];
 
PushTree[[subtree[subNode]]];  PushTree[MakeTreeLiteral[n]]};
 
sequence => {
copy: Tree.Link = IdentityMap[tb[subNode].son[1]];
cNode: Tree.Index = NARROW[copy, Tree.Link.subtree].index;
PushTree[tb[subNode].son[1]];  PushTree[MakeTreeLiteral[0]];
PushNode[seqindex, 2];  SetInfo[UnderType[t.componentType]];
SetAttr[2, long];  SetAttr[3, FALSE];
tb[subNode].son[1] ← PopTree[];  PushTree[[subtree[subNode]]];
tb[cNode].son[2] ← FreeTree[tb[cNode].son[2]];
tb[cNode].son[2] ← [symbol[index: t.tagSei]];
tb[cNode].info ← dataPtr.typeCARDINAL;
PushTree[copy]};
 
record => {  
-- StringBody only (compatibility glitch)
copy: Tree.Link = IdentityMap[tb[subNode].son[1]];
sei: Symbols.ISEIndex = NextSe[NextSe[FirstCtxSe[t.fieldCtx]]];
PushTree[tb[subNode].son[1]];  PushSe[sei];  PushNode[dollar, 2];
SetInfo[UnderType[seb[sei].idType]];  SetAttr[2, long];
tb[subNode].son[1] ← PopTree[];  PushTree[[subtree[subNode]]];
PushTree[copy];  PushSe[NextSe[FirstCtxSe[t.fieldCtx]]];  PushNode[dollar, 2];
SetInfo[dataPtr.typeCARDINAL]; SetAttr[2, long]};
 
ENDCASE => {
Log.ErrorTree[typeClash, tb[subNode].son[1]];
PushTree[[subtree[subNode]]];  PushTree[Tree.Null]};
 
 
PushTree[Tree.Null];  PushNode[list, 3];  tb[node].son[1] ← PopTree[];
VPush[0, [prop: prop, rep: other], MAX[RegsForType[tb[node].info], nRegs]];
RETURN [[subtree[index: node]]]};
 
DescList: 
PROC [node: Tree.Index] 
RETURNS [val: Tree.Link] = {
subNode: Tree.Index = GetNode[tb[node].son[1]];
type: CSEIndex = tb[node].info;
subType: CSEIndex;
prop: Prop;
nRegs: RegCount;
tb[subNode].son[1] ← RValue[tb[subNode].son[1], 0, unsigned];
nRegs ← VRegs[];  prop ← VProp[];  subType ← OperandType[tb[subNode].son[1]];
WITH seb[subType] 
SELECT 
FROM
ref =>
IF BitsForType[refType] 
MOD WordLength # 0 
THEN
Log.ErrorTree[nonAddressable, tb[subNode].son[1]];
 
 
ENDCASE;
 
tb[subNode].son[2] ← RValue[tb[subNode].son[2], 0, none];
nRegs ← MAX[VRegs[], nRegs];  prop ← CommonProp[VProp[], prop];
IF tb[subNode].son[3] # Tree.Null THEN TypeExp[tb[subNode].son[3]];
VPop[]; VPop[];
IF StructuredLiteral[tb[subNode].son[1]] 
AND TreeLiteral[tb[subNode].son[2]] 
THEN {
n: CARDINAL = WordsForType[type];
words: ValueDescriptor ← NEW[WordSeq[n]];
FillMultiWord[words, 0, tb[subNode].son[1]];
words[n-1] ← TreeLiteralValue[tb[subNode].son[2]];
PushLit[LiteralOps.FindDescriptor[DESCRIPTOR[@words[0], n]]];
PushNode[mwconst, 1];  SetInfo[type];
words ← NIL;
val ← PopTree[];  FreeNode[node]}
 
ELSE val ← [subtree[index: node]];
VPush[0, [prop: prop, rep: other], MAX[RegsForType[type], nRegs]];  RETURN};
 
}.