file Pass4S.mesa
last modified by Satterthwaite, May 6, 1983 3:33 pm
last modified by Sweet, January 21, 1981 10:50 PM
last modified by Donahue, 10-Dec-81 9:14:17
DIRECTORY
Alloc: TYPE USING [Notifier],
ComData: TYPE USING [
bodyIndex, globalFrameSize, interface, monitored, stopping, switches, textIndex,
typeBOOL, typeINT, typeLOCK],
Log: TYPE USING [Error, ErrorSei, ErrorTree],
LiteralOps: TYPE USING [Find, ResetLocalStrings],
P4: TYPE USING [
Attr, voidAttr, ConsState, Repr, none, unsigned, both, other,
AdjustBias, Assignment, BiasForType, BoolTest, BoolValue, Call, CheckBlock,
CommonProp, CommonRep, ConstantInterval, Cover, DeclItem, DeclUpdate,
Exp, Extract, Interval, LayoutBlock, LayoutGlobals, LayoutInterface, LayoutLocals,
MakeArgRecord, MakeTreeLiteral, NeutralExp, NormalizeRange,
OperandType, ProcessSymLiterals, RelTest, RepForType, Rhs, RValue,
TreeLiteral, TreeLiteralValue, VAttr, VBias, VPop, VProp, VRep, WordsForType,
EmptyInterval],
Pass4: TYPE USING [
implicitAttr, implicitBias, implicitType, lockNode, resident, resumeRecord, returnRecord],
PrincOps: TYPE USING [StateVector, EPRange, localbase],
Symbols: TYPE USING [
Base, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, BTIndex, CBTIndex, BodyInfo,
ContextLevel, ISENull, CSENull, RecordSENull, CTXNull, RootBti, BTNull, lG, lL,
typeANY, WordLength, seType, ctxType, bodyType],
SymbolOps: TYPE USING [
ArgRecord, Cardinality, ContextVariant, DelinkBti, FirstCtxSe, NextSe, NormalType,
TransferTypes, TypeLink, UnderType],
SymLiteralOps: TYPE USING [DescribeRefLits, DescribeTypes],
Tree: TYPE USING [
Base, Index, Link, Map, NodeName, Scan, Test, Null, NullIndex, treeType],
TreeOps: TYPE USING [
FreeNode, FreeTree, GetNode, GetSe, IdentityMap, ListHead, ListLength, MakeList,
MakeNode, MarkShared, NthSon, OpName, PopTree, PushProperList, PushList,
PushLit, PushNode, PushTree, ReverseScanList, ReverseUpdateList, ScanList,
SearchList, SetAttr, SetInfo, UpdateList];
Pass4S: PROGRAM
IMPORTS
Log, LiteralOps, P4, SymbolOps, SymLiteralOps, TreeOps,
dataPtr: ComData, passPtr: Pass4
EXPORTS P4 = {
OPEN SymbolOps, Symbols, P4, TreeOps;
tb: Tree.Base; -- tree base address (local copy)
seb: Symbols.Base; -- se table base address (local copy)
ctxb: Symbols.Base; -- ctx table base address (local copy)
bb: Symbols.Base; -- body table base (local copy)
StmtNotify: PUBLIC Alloc.Notifier = {
called by allocator whenever table area is repacked
tb ← base[Tree.treeType];
seb ← base[seType]; ctxb ← base[ctxType]; bb ← base[bodyType]};
Repr: TYPE = P4.Repr;
none: Repr = P4.none;
bodies and blocks
currentLevel: PUBLIC ContextLevel;
currentBody: BTIndex;
checked: PUBLIC BOOL;
BodyList: PROC [firstBti: BTIndex] = {
nextBti: BTIndex;
FOR bti: BTIndex ← firstBti, nextBti UNTIL bti = BTNull DO
nextBti ← IF bb[bti].link.which = parent THEN BTNull ELSE bb[bti].link.index;
WITH bb[bti] SELECT FROM
Callable =>
IF ~inline OR (dataPtr.interface AND LocalBody[LOOPHOLE[bti]]) THEN
Body[LOOPHOLE[bti, CBTIndex]]
ELSE DelinkBti[bti];
ENDCASE => BodyList[bb[bti].firstSon];
ENDLOOP};
LocalBody: PROC [bti: CBTIndex] RETURNS [BOOL] = INLINE {
sei: ISEIndex = bb[bti].id;
RETURN [sei = ISENull OR ctxb[seb[sei].idCtx].ctxType = simple]};
Body: PUBLIC PROC [bti: CBTIndex] = {
oldBodyIndex: CBTIndex = dataPtr.bodyIndex;
oldLevel: ContextLevel = currentLevel;
saveChecked: BOOL = checked;
saveIndex: CARDINAL = dataPtr.textIndex;
saveCatchScope: BOOL = catchScope;
saveRecord: RecordSEIndex = passPtr.returnRecord;
node: Tree.Index = NARROW[bb[bti].info, BodyInfo.Internal].bodyTree;
sei: CSEIndex = bb[bti].ioType;
base, bound: CARDINAL;
initTree: Tree.Link;
inRecord: RecordSEIndex;
catchScope ← FALSE;
dataPtr.bodyIndex ← currentBody ← bti; dataPtr.textIndex ← bb[bti].sourceIndex;
currentLevel ← IF bti = RootBti THEN lG ELSE bb[bti].level;
checked ← tb[node].attr1;
IF dataPtr.interface AND bb[bti].level > lL
THEN Log.ErrorSei[nonDefinition, bb[bti].id];
[inRecord, passPtr.returnRecord] ← TransferTypes[bb[bti].ioType];
IF ~bb[bti].hints.argUpdated THEN SetImmutable[inRecord, TRUE];
[] ← LiteralOps.ResetLocalStrings[];
bb[bti].hints.noStrings ← TRUE; -- see MarkString, below
IF tb[node].son[4] # Tree.Null THEN {
tb[node].son[4] ← Exp[tb[node].son[4], none]; VPop[]};
tb[node].son[1] ← UpdateList[tb[node].son[1], OpenItem];
[init: initTree, decls: tb[node].son[2]] ← ScanDecls[tb[node].son[2]];
IF bti = RootBti THEN {
fragments: BOOL
(SymLiteralOps.DescribeTypes[].length + SymLiteralOps.DescribeRefLits[].length) # 0;
dataPtr.globalFrameSize ←
(LayoutGlobals[bti, dataPtr.stopping, fragments] + (WordLength-1))/WordLength;
IF bb[bti].type # RecordSENull THEN
seb[bb[bti].type].length ← dataPtr.globalFrameSize*WordLength;
ProcessSymLiterals[];
base ← PrincOps.localbase*WordLength;
IF dataPtr.monitored AND tb[passPtr.lockNode].attr1 THEN {
PushTree[tb[passPtr.lockNode].son[2]];
PushLit[LiteralOps.Find[100000b]]; PushNode[cast, 1];
SetInfo[dataPtr.typeLOCK];
PushNode[assign, 2]; SetAttr[1, TRUE];
initTree ← Prefix[PopTree[], initTree]}}
ELSE {
base ← LayoutLocals[bti];
IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].length ← base;
IF bb[bti].firstSon # BTNull THEN
initTree ← Prefix[BodyInitList[bb[bti].firstSon], initTree]};
IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].mark4 ← TRUE;
tb[node].son[3] ← UpdateList[tb[node].son[3], Stmt];
bound ← AssignSubBlocks[bti, base];
WITH bb[bti].info SELECT FROM
Internal => {
frameSize ← (bound + (WordLength-1))/WordLength;
thread ← LiteralOps.ResetLocalStrings[]};
ENDCASE;
bb[bti].resident ← passPtr.resident;
IF bb[bti].firstSon # BTNull THEN BodyList[bb[bti].firstSon];
tb[node].son[1] ← ReverseUpdateList[tb[node].son[1], CloseItem];
tb[node].son[2] ← Prefix[initTree, UpdateList[tb[node].son[2], DeclUpdate]];
IF dataPtr.interface AND bti = RootBti THEN {
n: CARDINAL = LayoutInterface[bti];
WITH t: seb[bb[bti].ioType] SELECT FROM
definition => t.nGfi ← IF n=0 THEN 1 ELSE (n-1)/PrincOps.EPRange + 1;
ENDCASE};
SetImmutable[inRecord, FALSE];
catchScope ← saveCatchScope;
currentBody ← dataPtr.bodyIndex ← oldBodyIndex;
currentLevel ← oldLevel; checked ← saveChecked;
dataPtr.textIndex ← saveIndex; passPtr.returnRecord ← saveRecord};
MarkString: PUBLIC PROC [local: BOOL] = {
bb[IF local THEN dataPtr.bodyIndex ELSE RootBti].hints.noStrings ← FALSE};
SetImmutable: PROC [rSei: RecordSEIndex, b: BOOL] = {
IF rSei # RecordSENull THEN
FOR sei: ISEIndex ← FirstCtxSe[seb[rSei].fieldCtx], NextSe[sei] UNTIL sei = ISENull DO
seb[sei].immutable ← b;
ENDLOOP};
ScanDecls: PROC [t: Tree.Link] RETURNS [init, decls: Tree.Link] = {
IF OpName[t] = initlist THEN {
node: Tree.Index = GetNode[t];
init ← UpdateList[tb[node].son[1], Stmt]; tb[node].son[1] ← Tree.Null;
decls ← tb[node].son[2]; tb[node].son[2] ← Tree.Null;
FreeNode[node]}
ELSE {init ← Tree.Null; decls ← t};
ScanList[decls, DeclItem]; RETURN};
Prefix: PROC [first, rest: Tree.Link] RETURNS [Tree.Link] = {
SELECT TRUE FROM
(first = Tree.Null) => RETURN [rest];
(rest = Tree.Null) => RETURN [first];
ENDCASE => {PushTree[first]; PushTree[rest]; RETURN [MakeList[2]]}};
BodyInitList: PROC [firstBti: BTIndex] RETURNS [Tree.Link] = {
bti: BTIndex ← firstBti;
n: CARDINAL ← 0;
IF bti # BTNull THEN
DO
WITH body: bb[bti] SELECT FROM
Callable =>
IF ~body.inline THEN {PushNode[procinit, 0]; SetInfo[bti]; n ← n+1};
ENDCASE => NULL;
IF bb[bti].link.which = parent THEN EXIT;
bti ← bb[bti].link.index;
ENDLOOP;
RETURN [MakeList[n]]};
AssignSubBlocks: PROC [rootBti: BTIndex, base: CARDINAL] RETURNS [bound: CARDINAL] = {
level: ContextLevel = bb[rootBti].level;
bti: BTIndex;
bound ← base;
IF (bti ← bb[rootBti].firstSon) # BTNull THEN
DO
SELECT bb[bti].kind FROM
Other =>
IF bb[bti].level = level THEN {
length: CARDINAL = AssignBlock[bti, base];
bound ← MAX[length, bound]};
ENDCASE => NULL;
IF bb[bti].link.which = parent THEN EXIT;
bti ← bb[bti].link.index;
ENDLOOP;
RETURN};
Subst: PUBLIC PROC [node: Tree.Index] RETURNS [Tree.Link] = {
OPEN tb[node];
saveRecord: RecordSEIndex = passPtr.returnRecord;
saveChecked: BOOL = checked;
son[1] ← NeutralExp[son[1]];
passPtr.returnRecord ← TransferTypes[OperandType[son[1]]].typeOut;
IF ~attr3 THEN checked ← attr1;
son[2] ← UpdateList[son[2], Stmt];
checked ← saveChecked; passPtr.returnRecord ← saveRecord;
RETURN [[subtree[index: node]]]};
Scope: PROC [node: Tree.Index, item: Tree.Map] RETURNS [Tree.Link] = {
OPEN tb[node];
bti: BTIndex = info;
saveIndex: CARDINAL = dataPtr.textIndex;
oldBodyIndex: BTIndex = currentBody;
oldLevel: ContextLevel = currentLevel;
initTree: Tree.Link;
dataPtr.textIndex ← bb[bti].sourceIndex;
currentBody ← bti; currentLevel ← bb[bti].level;
[init: initTree, decls: son[1]] ← ScanDecls[son[1]];
IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].mark4 ← TRUE;
CheckBlock[bti];
son[2] ← UpdateList[son[2], item];
son[1] ← Prefix[initTree, UpdateList[son[1], DeclUpdate]];
IF catchScope THEN catchBound ← MAX[AssignBlock[bti, catchBase], catchBound];
currentBody ← oldBodyIndex; currentLevel ← oldLevel;
dataPtr.textIndex ← saveIndex;
RETURN [[subtree[index: node]]]};
AssignBlock: PROC [bti: BTIndex, base: CARDINAL] RETURNS [bound: CARDINAL] = {
node: Tree.Index;
newBase: CARDINAL = LayoutBlock[bti, base];
initTree: Tree.Link = IF bb[bti].firstSon # BTNull
THEN BodyInitList[bb[bti].firstSon]
ELSE Tree.Null;
IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].length ← newBase;
bound ← AssignSubBlocks[bti, newBase];
WITH bb[bti].info SELECT FROM
Internal => {frameSize ← (bound + (WordLength-1))/WordLength; node ← bodyTree};
ENDCASE => NULL;
IF initTree # Tree.Null THEN tb[node].son[1] ← Prefix[initTree, tb[node].son[1]];
RETURN};
main dispatch
Stmt: PROC [stmt: Tree.Link] RETURNS [val: Tree.Link] = {
node: Tree.Index;
saveIndex: CARDINAL = dataPtr.textIndex;
val ← stmt;  -- the default case
WITH stmt SELECT FROM
subtree => {
node ← index;
IF node # Tree.NullIndex THEN {
OPEN tb[node];
dataPtr.textIndex ← info;
SELECT name FROM
assign => {val ← Assignment[node]; VPop[]};
extract => val ← ExtractStmt[node];
call, portcall, signal, error, xerror, start, join => {val ← Call[node]; VPop[]};
subst => val ← Subst[node];
block => {
saveChecked: BOOL = checked;
checked ← tb[node].attr1; val ← Scope[node, Stmt];
checked ← saveChecked};
if => val ← IfStmt[node];
case => val ← CaseDriver[node, Stmt, 0];
bind =>
val ← IF attr3 THEN BindType[node, Stmt] ELSE BindCase[node, case, BindStmt];
do => val ← DoStmt[node];
return, result => Return[node, passPtr.returnRecord];
resume => Return[node, passPtr.resumeRecord];
label => {son[1] ← Stmt[son[1]]; son[2] ← UpdateList[son[2], Stmt]};
open => {
son[1] ← UpdateList[son[1], OpenItem];
son[2] ← UpdateList[son[2], Stmt];
son[1] ← ReverseUpdateList[son[1], CloseItem]};
checked => {
saveChecked: BOOL = checked;
checked ← attr1; son[1] ← Stmt[son[1]];
checked ← saveChecked};
enable => {CatchPhrase[son[1]]; son[2] ← Stmt[son[2]]};
catchmark => son[1] ← Stmt[son[1]];
lock => {son[1] ← UpdateList[son[1], Stmt]; son[2] ← Exp[son[2], none]; VPop[]};
notify, broadcast, unlock => {son[1] ← Exp[son[1], none]; VPop[]};
wait => {
son[1] ← Exp[son[1], none]; VPop[];
son[2] ← Exp[son[2], none]; VPop[];
IF nSons > 2 THEN CatchNest[son[3]]};
restart => {son[1] ← NeutralExp[son[1]]; IF nSons > 2 THEN CatchNest[son[3]]};
dst, lst, lste, lstf => {
son[1] ← Exp[son[1], none];
IF WordsForType[OperandType[son[1]]] < PrincOps.StateVector.SIZE THEN
Log.ErrorTree[sizeClash, son[1]];
VPop[]};
goto, exit, loop, syserror, reject, continue, retry, stop, null => NULL;
free => val ← Free[node];
apply => NULL;
item => son[2] ← Stmt[son[2]];
list => val ← UpdateList[stmt, Stmt];
ENDCASE => Log.Error[unimplemented]}};
ENDCASE => ERROR;
dataPtr.textIndex ← saveIndex; RETURN};
extraction
ExtractStmt: PROC [node: Tree.Index] RETURNS [val: Tree.Link] = {
subNode: Tree.Index = GetNode[tb[node].son[1]];
rType: RecordSEIndex = tb[subNode].info;
IF rType # Symbols.RecordSENull THEN {val ← Extract[node]; VPop[]}
ELSE {
val ← Stmt[tb[node].son[2]]; tb[node].son[2] ← Tree.Null;
WITH val SELECT FROM subtree => tb[index].info ← tb[node].info ENDCASE;
FreeNode[node]};
RETURN};
return
Return: PROC [node: Tree.Index, type: RecordSEIndex] = {
tb[node].son[1] ← IF tb[node].attr3 AND type # RecordSENull
THEN Rhs[tb[node].son[1], type]
ELSE MakeArgRecord[type, tb[node].son[1]];
VPop[]};
conditionals
IfStmt: PROC [node: Tree.Index] RETURNS [val: Tree.Link] = {
OPEN tb[node];
son[1] ← BoolValue[son[1]]; VPop[];
son[2] ← Stmt[son[2]]; son[3] ← Stmt[son[3]];
IF ~TreeLiteral[son[1]] THEN val ← Tree.Link[subtree[index: node]]
ELSE {
IF BoolTest[son[1]] THEN {val ← son[2]; son[2] ← Tree.Null}
ELSE {val ← son[3]; son[3] ← Tree.Null};
FreeNode[node]};
RETURN};
BindStmt: PROC [t: Tree.Link, labelBias: INTEGER] RETURNS [Tree.Link] = {
node: Tree.Index = GetNode[t];
RETURN [CaseDriver[GetNode[t], Stmt, labelBias]]};
drivers for processing selections
BindType: PUBLIC PROC [node: Tree.Index, eval: Tree.Map] RETURNS [Tree.Link] = {
OPEN tb[node];
saveType: CSEIndex = passPtr.implicitType;
saveBias: INTEGER = passPtr.implicitBias;
saveAttr: Attr = passPtr.implicitAttr;
Item: Tree.Map = {RETURN [Scope[GetNode[t], eval]]};
subNode: Tree.Index ← GetNode[son[1]];
type: CSEIndex = OperandType[tb[subNode].son[2]];
PushTree[RValue[tb[subNode].son[2], BiasForType[type], RepForType[type]]];
passPtr.implicitType ← type;
passPtr.implicitAttr ← VAttr[]; passPtr.implicitBias ← VBias[]; VPop[];
tb[subNode].son[2] ← Tree.Null;
PushTree[UpdateList[son[3], Item]]; son[3] ← Tree.Null;
PushTree[eval[son[4]]]; son[4] ← Tree.Null;
PushNode[name, 3]; SetInfo[info]; SetAttr[1, attr1]; SetAttr[2, attr2];
FreeNode[node];
passPtr.implicitAttr ← saveAttr; passPtr.implicitBias ← saveBias;
passPtr.implicitType ← saveType;
RETURN [PopTree[]]};
BindCase: PUBLIC PROC [
node: Tree.Index,
op: Tree.NodeName,
eval: PROC [Tree.Link, INTEGER] RETURNS [Tree.Link]]
RETURNS [val: Tree.Link] = {
OPEN tb[node];
labelBias: INTEGER = TagBias[BoundType[son[1]], TestCtx[ListHead[son[3]]]];
subNode: Tree.Index;
PushTree[son[2]]; son[2] ← Tree.Null;
PushTree[son[3]]; son[3] ← Tree.Null;
PushTree[son[4]]; son[4] ← Tree.Null;
PushTree[OpenItem[son[1]]]; son[1] ← Tree.Null;
PushNode[op, 4]; SetInfo[info];
SetAttr[1, FALSE]; SetAttr[2, FALSE]; SetAttr[3, attr3];
val ← eval[PopTree[], labelBias]; subNode ← GetNode[val];
tb[subNode].son[4] ← CloseItem[tb[subNode].son[4]];
FreeNode[node];
RETURN};
BoundType: PROC [base: Tree.Link] RETURNS [CSEIndex] = INLINE {
RETURN [DerefType[OperandType[NthSon[base, 2]]]]};
TestCtx: PROC [item: Tree.Link] RETURNS [CTXIndex] = INLINE {
RETURN [IF item = Tree.Null
THEN CTXNull
ELSE seb[GetSe[NthSon[ListHead[NthSon[item, 1]], 2]]].idCtx]};
TagBias: PROC [rType: CSEIndex, testCtx: CTXIndex] RETURNS [INTEGER] = {
FOR subType: CSEIndex ← rType, UnderType[TypeLink[subType]]
WHILE subType # CSENull DO
WITH t: seb[subType] SELECT FROM
record =>
IF t.hints.variant THEN {
sei: ISEIndex = ContextVariant[t.fieldCtx];
uType: CSEIndex = UnderType[seb[sei].idType];
WITH u: seb[uType] SELECT FROM
union =>
IF u.caseCtx = testCtx OR testCtx = CTXNull THEN
RETURN [BiasForType[UnderType[seb[u.tagSei].idType]]];
ENDCASE};
ENDCASE => EXIT;
ENDLOOP;
ERROR};
CaseDriver: PUBLIC PROC [node: Tree.Index, selection: Tree.Map, labelBias: INTEGER]
RETURNS [val: Tree.Link] = {
OPEN tb[node];
saveType: CSEIndex = passPtr.implicitType;
saveBias: INTEGER = passPtr.implicitBias;
saveAttr: Attr = passPtr.implicitAttr;
type: CSEIndex = OperandType[son[1]];
son[1] ← Exp[son[1], none];
IF attr2 THEN {    -- not bind/bindx
found: BOOLFALSE;
EvalTest: Tree.Map = {
subNode: Tree.Index = GetNode[t];
IF tb[subNode].son[1] # Tree.Null THEN ERROR;
tb[subNode].son[1] ← IdentityMap[tb[node].son[1]];
v ← BoolValue[t]; VPop[];
IF BoolTest[v] THEN found ← TRUE;
RETURN};
TestItem: Tree.Test = {
subNode: Tree.Index = GetNode[t];
tb[subNode].son[1] ← UpdateList[tb[subNode].son[1], EvalTest];
IF found THEN {val ← tb[subNode].son[2]; tb[subNode].son[2] ← Tree.Null};
RETURN [found]};
SearchList[son[2], TestItem];
IF ~found THEN {val ← son[3]; son[3] ← Tree.Null};
FreeNode[node];
val ← selection[val]}
ELSE IF type = dataPtr.typeBOOL AND attr1 AND TreeLiteral[son[1]] THEN {
CaseItem: Tree.Scan = {
subNode: Tree.Index = GetNode[t];
started: BOOL;
PushTest: Tree.Scan = {
tNode: Tree.Index = GetNode[t];
PushTree[tb[tNode].son[2]]; tb[tNode].son[2] ← Tree.Null;
IF ~BoolTest[son[1]] THEN PushNode[not, 1];
IF started THEN PushNode[or, 2];
started ← TRUE; RETURN};
PushTree[tb[subNode].son[2]]; tb[subNode].son[2] ← Tree.Null;
started ← FALSE; ScanList[tb[subNode].son[1], PushTest];
IF selection = Stmt THEN {PushNode[if, -3]; SetInfo[tb[subNode].info]}
ELSE {PushNode[ifx, -3]; SetInfo[tb[node].info]};
RETURN};
son[1] ← AdjustBias[son[1], -VBias[]]; VPop[];
PushTree[son[3]]; son[3] ← Tree.Null;
ReverseScanList[son[2], CaseItem];
FreeNode[node];
passPtr.implicitAttr ← voidAttr;
val ← selection[PopTree[]]}
ELSE {
nSons: CARDINAL = ListLength[son[2]];
i, j, first, last, next, newSons: CARDINAL;
min, max: INTEGER;
minTree, maxTree: Tree.Link;
rep: Repr;
subNode, listNode: Tree.Index;
switchable, copying: BOOL;
multiword: BOOL = WordsForType[type] # 1;
count: CARDINAL;
TestExp: Tree.Map = {
v ← RValue[t, 0, none];
passPtr.implicitAttr.prop ← CommonProp[passPtr.implicitAttr.prop, VProp[]];
VPop[]};
SwitchValue: Tree.Map = {
val: Tree.Link;
tNode: Tree.Index = GetNode[t];
val ← tb[tNode].son[2] ← RValue[tb[tNode].son[2], passPtr.implicitBias, rep];
passPtr.implicitAttr.prop ← CommonProp[passPtr.implicitAttr.prop, VProp[]];
VPop[];
IF count = 0 THEN {first ← i; minTree ← maxTree ← val}
ELSE {
subRep: Repr = (SELECT rep FROM other, none => unsigned, ENDCASE => rep);
IF RelTest[val, minTree, relL, subRep] THEN minTree ← val;
IF RelTest[val, maxTree, relG, subRep] THEN maxTree ← val};
count ← count + 1;
RETURN [t]};
passPtr.implicitType ← type;
passPtr.implicitBias ← VBias[] - labelBias;
passPtr.implicitAttr ← VAttr[]; rep ← passPtr.implicitAttr.rep; VPop[];
newSons ← nSons;
i ← next ← 1; copying ← FALSE; listNode ← GetNode[son[2]];
UNTIL i > nSons DO
WHILE i <= nSons DO
subNode ← GetNode[tb[listNode].son[i]];
IF tb[subNode].attr1 AND ~multiword THEN EXIT;
tb[subNode].son[1] ← UpdateList[tb[subNode].son[1], TestExp];
tb[subNode].son[2] ← selection[tb[subNode].son[2]];
i ← i+1;
ENDLOOP;
switchable ← FALSE; count ← 0;
WHILE i <= nSons DO -- N.B. implicitbias is never changed by this loop
subNode ← GetNode[tb[listNode].son[i]];
IF ~tb[subNode].attr1 OR multiword THEN EXIT;
tb[subNode].son[1] ← UpdateList[tb[subNode].son[1], SwitchValue];
tb[subNode].son[2] ← selection[tb[subNode].son[2]];
switchable ← TRUE; last ← i; i ← i+1;
ENDLOOP;
IF switchable
AND SwitchWorthy[count,
(max←TreeLiteralValue[maxTree])-(min←TreeLiteralValue[minTree])] THEN {
copying ← TRUE;
FOR j IN [next .. first) DO PushTree[tb[listNode].son[j]] ENDLOOP;
PushTree[AdjustBias[Tree.Null, min]];
PushTree[MakeTreeLiteral[max-min+1]];
FOR j IN [first .. last] DO PushTree[SwitchTree[tb[listNode].son[j], min]] ENDLOOP;
PushProperList[last-first+1];
PushNode[caseswitch, 3];
next ← last+1; newSons ← newSons - (last-first)};
ENDLOOP;
IF copying THEN {
FOR j IN [next .. nSons] DO PushTree[tb[listNode].son[j]] ENDLOOP;
PushProperList[newSons]; son[2] ← PopTree[]};
son[3] ← selection[son[3]];
val ← Tree.Link[subtree[index: node]]};
passPtr.implicitAttr ← saveAttr; passPtr.implicitBias ← saveBias;
passPtr.implicitType ← saveType;
RETURN};
auxiliary routines for CaseDriver
SwitchWorthy: PROC [entries, delta: CARDINAL] RETURNS [BOOL] = {
the decision function for using a switch
RETURN [delta < 77777b AND delta+6 < 3*entries]};
SwitchTree: PROC [t: Tree.Link, offset: INTEGER] RETURNS [Tree.Link] = {
node: Tree.Index = GetNode[t];
count: CARDINAL;
PushSwitchEntry: Tree.Scan = {
subNode: Tree.Index = GetNode[t];
count ← count+1;
PushTree[MakeTreeLiteral[TreeLiteralValue[tb[subNode].son[2]]-offset]]};
count ← 0; ScanList[tb[node].son[1], PushSwitchEntry];
PushList[count]; PushTree[tb[node].son[2]];
tb[node].son[2] ← Tree.Null; FreeNode[node];
RETURN [MakeNode[casetest, 2]]};
iterative statements
DoStmt: PROC [node: Tree.Index] RETURNS [val: Tree.Link] = {
OPEN tb[node];
void: BOOLFALSE;
bti: BTIndex ← BTNull;
IF son[1] # Tree.Null THEN [bti, void] ← ForClause[GetNode[son[1]]];
IF son[2] # Tree.Null THEN {
son[2] ← BoolValue[son[2]];
IF TreeLiteral[son[2]] THEN {
IF BoolTest[son[2]] THEN son[2] ← FreeTree[son[2]] ELSE void ← TRUE};
VPop[]};
son[3] ← UpdateList[son[3], OpenItem];
son[4] ← UpdateList[son[4], Stmt];
son[5] ← UpdateList[son[5], Stmt];
son[6] ← UpdateList[son[6], Stmt];
son[3] ← ReverseUpdateList[son[3], CloseItem];
IF catchScope AND bti # BTNull THEN
catchBound ← MAX[AssignBlock[bti, catchBase], catchBound];
IF ~void THEN val ← [subtree[index: node]]
ELSE {val ← son[6]; son[6] ← Tree.Null; FreeNode[node]};
RETURN};
ForClause: PROC [node: Tree.Index] RETURNS [bti: BTIndex, void: BOOL] = {
idBias: INTEGER;
idRep, rep: Repr;
idType, type1, type2: CSEIndex;
iNode: Tree.Index;
range: CARDINAL;
cs: ConsState ← $first;
void ← FALSE; bti ← tb[node].info;
IF tb[node].son[1] = Tree.Null THEN {
idType ← dataPtr.typeINT; idBias ← 0; idRep ← both}
ELSE {
IF OpName[tb[node].son[1]] = decl THEN {
subNode: Tree.Index ← GetNode[tb[node].son[1]];
ScanList[tb[node].son[1], DeclItem];
tb[node].son[1] ← tb[subNode].son[1];
tb[subNode].son[1] ← Tree.Null; FreeNode[subNode];
cs ← $init};
idType ← OperandType[tb[node].son[1]];
tb[node].son[1] ← Exp[tb[node].son[1], none];
idBias ← VBias[]; idRep ← VRep[]; VPop[]};
SELECT tb[node].name FROM
forseq => {
tb[node].son[2] ← Rhs[tb[node].son[2], idType, cs]; VPop[];
tb[node].son[3] ← Rhs[tb[node].son[3], idType, $first]; VPop[]};
upthru, downthru => {
tb[node].son[2] ← NormalizeRange[tb[node].son[2]];
iNode ← GetNode[tb[node].son[2]];
type1 ← OperandType[tb[iNode].son[1]];
type2 ← OperandType[tb[iNode].son[2]];
tb[node].attr1 ← Interval[iNode, idBias, idRep].const AND seb[idType].typeTag # long;
IF tb[node].attr1 AND ~tb[iNode].attr2 THEN
[] ← ConstantInterval[iNode ! EmptyInterval => {void ← TRUE; RESUME}];
rep ← CommonRep[VRep[], idRep];
tb[iNode].attr3 ← rep # unsigned; VPop[];
IF rep = none OR (rep = unsigned AND idBias > 0) THEN
Log.ErrorTree[mixedRepresentation, tb[node].son[2]];
SELECT TRUE FROM
void => NULL;
(WordsForType[idType] = 0) => Log.ErrorTree[sizeClash, tb[node].son[1]];
(idType # dataPtr.typeINT) AND (idType # typeANY) => {
OPEN tb[iNode];
range ← Cardinality[idType];
IF (checked OR dataPtr.switches['b]) AND range # 0 THEN
IF (Cover[idType, idRep, type1, rep] # full AND RangeTest[son[1], range] # in)
OR
(Cover[idType, idRep, type2, rep] # full AND RangeTest[son[2], range] # in) THEN
tb[node].son[3] ← MakeTreeLiteral[range];
IF name = intCC AND type2 # dataPtr.typeINT THEN
IF TreeLiteral[son[1]] AND
INTEGER[TreeLiteralValue[son[1]]]+idBias <= BiasForType[type2] THEN
tb[node].attr1 ← TRUE;
IF tb[node].attr1 AND range # 0 THEN { -- nonvoid interval
IF (name=intCC OR name=intCO) AND RangeTest[son[1], range] = out THEN
Log.ErrorTree[boundsFault, son[1]];
IF (name=intCC OR name=intOC) AND RangeTest[son[2], range] = out THEN
Log.ErrorTree[boundsFault, son[2]]}};
ENDCASE};
ENDCASE => ERROR;
RETURN};
RangeTest: PROC [t: Tree.Link, range: CARDINAL] RETURNS [{in, out, unknown}] = {
RETURN [IF TreeLiteral[t]
THEN IF TreeLiteralValue[t] < range THEN in ELSE out
ELSE unknown]};
free
Free: PROC [node: Tree.Index] RETURNS [Tree.Link] = {
OPEN tb[node];
vType, pType: CSEIndex;
IF son[1] # Tree.Null THEN {son[1] ← Exp[son[1], none]; VPop[]};
son[2] ← NeutralExp[son[2]];
vType ← OperandType[son[2]]; pType ← DerefType[vType];
IF OpName[son[2]] = addr THEN {
subNode: Tree.Index = GetNode[son[2]];
son[2] ← tb[subNode].son[1]; tb[subNode].son[1] ← Tree.Null; FreeNode[subNode]}
ELSE {
PushTree[son[2]]; PushNode[uparrow, 1]; SetInfo[pType];
SetAttr[1, checked OR dataPtr.switches['n]];
SetAttr[2, seb[vType].typeTag = long];
son[2] ← PopTree[]};
tb[node].son[3] ← MakeTreeLiteral[WordsForType[DerefType[pType]]];
IF nSons > 3 THEN CatchNest[son[4]];
RETURN [[subtree[index: node]]]};
basing
DerefType: PROC [type: CSEIndex] RETURNS [CSEIndex] = {
subType: CSEIndex = NormalType[type];
RETURN [WITH seb[subType] SELECT FROM
ref => UnderType[refType],
ENDCASE => type]};
OpenItem: Tree.Map = {
node: Tree.Index = GetNode[t];
IF OpName[tb[node].son[2]] # openx THEN v ← Tree.Null
ELSE {v ← NeutralExp[tb[node].son[2]]; tb[node].son[2] ← Tree.Null};
FreeNode[node];
RETURN};
CloseItem: Tree.Map = {
node: Tree.Index;
IF bb[currentBody].firstSon # BTNull OR OpName[t] # openx THEN v ← t
ELSE {
MarkShared[t, FALSE]; node ← GetNode[t];
v ← tb[node].son[1]; tb[node].son[1] ← Tree.Null; FreeNode[node]};
RETURN};
catch phrases
CatchFrameBase: CARDINAL = (PrincOps.localbase+1)*WordLength;
catchScope: BOOL;
catchBase: CARDINAL;
catchBound: CARDINAL;
CatchNest: PUBLIC PROC [t: Tree.Link] = {
IF t # Tree.Null THEN CatchPhrase[t]};
CatchPhrase: PROC [t: Tree.Link] = {
node: Tree.Index = GetNode[t];
saveCatchScope: BOOL = catchScope;
saveCatchBase: CARDINAL = catchBase;
saveCatchBound: CARDINAL = catchBound;
bound: CARDINAL;
CatchTest: Tree.Map = {
PushTree[Tree.Null]; PushTree[Exp[t, none]]; VPop[];
PushNode[relE, 2]; SetInfo[dataPtr.typeBOOL];
RETURN [PopTree[]]};
CatchItem: Tree.Scan = {
node: Tree.Index = GetNode[t];
type: CSEIndex = tb[node].info;
saveRecord: RecordSEIndex = passPtr.resumeRecord;
tb[node].son[1] ← UpdateList[tb[node].son[1], CatchTest];
catchBase ← CatchFrameBase;
IF type = CSENull THEN passPtr.resumeRecord ← RecordSENull
ELSE
WITH t: seb[type] SELECT FROM
transfer => {
passPtr.resumeRecord ← ArgRecord[t.typeOut];
catchBase ← catchBase +
ArgLength[ArgRecord[t.typeIn]] + ArgLength[passPtr.resumeRecord]};
ENDCASE => ERROR;
catchBound ← catchBase;
tb[node].son[2] ← Stmt[tb[node].son[2]];
bound ← MAX[bound, catchBound];
passPtr.resumeRecord ← saveRecord};
catchScope ← TRUE; currentLevel ← currentLevel + 1;
bound ← CatchFrameBase + WordLength;
ScanList[tb[node].son[1], CatchItem];
IF tb[node].nSons > 1 THEN {
catchBound ← catchBase ← CatchFrameBase;
tb[node].son[2] ← Stmt[tb[node].son[2]];
bound ← MAX[bound, catchBound]};
tb[node].info ← (bound + (WordLength-1))/WordLength;
catchBase ← saveCatchBase; catchBound ← saveCatchBound;
currentLevel ← currentLevel - 1; catchScope ← saveCatchScope};
ArgLength: PROC [rSei: RecordSEIndex] RETURNS [CARDINAL] = {
RETURN [IF rSei = RecordSENull THEN 0 ELSE seb[rSei].length]};
}.