-- file Pass4Ops.Mesa
-- last written by Satterthwaite, October 30, 1979 3:05 PM
DIRECTORY
Literals: FROM "literals" USING [LitDescriptor, ltType],
LiteralOps: FROM "literalops"
USING [DescriptorValue, Find, FindDescriptor, Value],
Log: FROM "log" USING [ErrorTree],
P4: FROM "p4"
USING [
RelOp, Repr, none, unsigned, both, other,
TreeLiteral, StructuredLiteral],
Pass4: FROM "pass4" USING [tFALSE, tTRUE],
Symbols: FROM "symbols" USING [CSEIndex],
Table: FROM "table" USING [Base, Notifier],
Tree: FROM "tree" USING [treeType, Index, Link, Map, NodeName, Null, Scan],
TreeOps: FROM "treeops"
USING [
FreeNode, GetNode, PopTree, PushLit, PushNode,
ScanList, SetInfo, UpdateList];
Pass4Ops: PROGRAM
IMPORTS LiteralOps, Log, P4, TreeOps, passPtr: Pass4
EXPORTS P4 =
BEGIN
OPEN TreeOps;
RelOp: TYPE = P4.RelOp;
Repr: TYPE = P4.Repr;
tb: Table.Base; -- tree base address (local copy)
ltb: Table.Base; -- literal table base address (local copy)
OpsNotify: PUBLIC Table.Notifier =
BEGIN -- called by allocator whenever table area is repacked
tb ← base[Tree.treeType]; ltb ← base[Literals.ltType];
END;
-- literals
TreeLiteralValue: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [WORD] =
BEGIN
node: Tree.Index;
DO
WITH e:t SELECT FROM
literal =>
WITH e.info SELECT FROM
word => RETURN [LiteralOps.Value[index]];
ENDCASE => EXIT;
subtree =>
BEGIN node ← e.index;
SELECT tb[node].name FROM
cast => t ← tb[node].son[1];
ENDCASE => EXIT;
END;
ENDCASE => EXIT
ENDLOOP;
ERROR;
END;
MakeTreeLiteral: PUBLIC PROCEDURE [val: WORD] RETURNS [Tree.Link] =
BEGIN
RETURN [[literal[info: [word[index: LiteralOps.Find[val]]]]]]
END;
TreeLiteralDesc: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [Literals.LitDescriptor] =
BEGIN
WITH t SELECT FROM
literal =>
WITH info SELECT FROM
word => RETURN [LiteralOps.DescriptorValue[index]];
ENDCASE;
subtree =>
BEGIN
node: Tree.Index = index;
SELECT tb[node].name FROM
mwconst, cast => RETURN [TreeLiteralDesc[tb[node].son[1]]];
ENDCASE;
END;
ENDCASE;
ERROR
END;
LongLiteralValue: PROCEDURE [t: Tree.Link] RETURNS [LONG UNSPECIFIED] =
BEGIN
w: ARRAY [0..1] OF WORD;
desc: Literals.LitDescriptor = TreeLiteralDesc[t];
IF desc.length # 2 THEN ERROR;
w[0] ← ltb[desc.offset][0]; w[1] ← ltb[desc.offset][1];
RETURN [LOOPHOLE[w]]
END;
MakeLongLiteral: PROCEDURE [val: LONG UNSPECIFIED, type: Symbols.CSEIndex]
RETURNS [Tree.Link] =
BEGIN
w: ARRAY [0..1] OF WORD ← LOOPHOLE[val];
PushLit[LiteralOps.FindDescriptor[DESCRIPTOR[w]]];
PushNode[mwconst, 1]; SetInfo[type];
RETURN [PopTree[]]
END;
LiteralRep: PUBLIC PROCEDURE [t: Tree.Link, rep: Repr] RETURNS [Repr] =
BEGIN
desc: Literals.LitDescriptor;
RETURN [SELECT TRUE FROM
rep = P4.other, rep = P4.none => rep,
P4.TreeLiteral[t] =>
IF TreeLiteralValue[t] > 77777B
THEN IF rep = P4.both THEN P4.unsigned ELSE rep
ELSE P4.both,
P4.StructuredLiteral[t] =>
IF (desc←TreeLiteralDesc[t]).length = 2
THEN
IF ltb[desc.offset][1] > 77777B
THEN IF rep = P4.both THEN P4.unsigned ELSE rep
ELSE P4.both
ELSE P4.other,
ENDCASE => rep]
END;
ZeroP: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [zero: BOOLEAN] =
BEGIN
IF ~P4.StructuredLiteral[t]
THEN zero ← FALSE
ELSE
BEGIN
desc: Literals.LitDescriptor = TreeLiteralDesc[t];
i: CARDINAL;
zero ← TRUE;
FOR i IN [0..desc.length) WHILE (zero←(ltb[desc.offset][i] = 0))
DO NULL ENDLOOP;
END;
RETURN
END;
-- dispatch
Mode: TYPE = {ss, su, ls, lu, other};
ModeMap: ARRAY Repr OF Mode =
[ss, ss, su, ss, ls, ls, lu, ls,
other, ss, su, ss, other, ls, lu, ls];
InOp: TYPE = Tree.NodeName [in .. notin];
IntOp: TYPE = Tree.NodeName [intOO .. intCC];
Test: ARRAY Mode OF
PROCEDURE [t1, t2: Tree.Link, op: RelOp] RETURNS [BOOLEAN] =
[TestSS, TestSU, TestLS, TestLU, TestOther];
UnaryOp: ARRAY Mode OF PROCEDURE [node: Tree.Index] RETURNS [Tree.Link] =
[UnarySS, UnarySU, UnaryLS, UnaryLU, OpError];
BinaryOp: ARRAY Mode OF PROCEDURE [node: Tree.Index] RETURNS [Tree.Link] =
[BinarySS, BinarySU, BinaryLS, BinaryLU, OpError];
FoldExpr: PUBLIC PROCEDURE [node: Tree.Index, rep: Repr] RETURNS [val: Tree.Link] =
BEGIN
SELECT tb[node].name FROM
plus, minus, times, div, mod => val ← BinaryOp[ModeMap[rep]][node];
abs, uminus => val ← UnaryOp[ModeMap[rep]][node];
relE, relN, relL, relGE, relG, relLE =>
BEGIN
val ← IF RelTest [
l: tb[node].son[1], r: tb[node].son[2],
op: tb[node].name,
rep: rep]
THEN passPtr.tTRUE
ELSE passPtr.tFALSE;
FreeNode[node];
END;
in, notin =>
BEGIN
val ← IF
IntervalTest [l: tb[node].son[1], r: tb[node].son[2], rep: rep]
=
(tb[node].name = in)
THEN passPtr.tTRUE
ELSE passPtr.tFALSE;
FreeNode[node];
END;
min, max =>
BEGIN
VoidItem: Tree.Map = BEGIN RETURN[IF t=val THEN Tree.Null ELSE t] END;
val ← Choose[
list: tb[node].son[1],
test: IF tb[node].name = min THEN relL ELSE relG,
rep: rep];
tb[node].son[1] ← UpdateList[tb[node].son[1], VoidItem];
FreeNode[node];
END;
ENDCASE => ERROR;
END;
RelTest: PUBLIC PROCEDURE [l, r: Tree.Link, op: RelOp, rep: Repr] RETURNS [BOOLEAN] =
BEGIN
OpMap: ARRAY RelOp OF RECORD [map: RelOp, sense: BOOLEAN] =
[[relE, TRUE], [relE, FALSE], [relL, TRUE], [relL, FALSE],
[relG, TRUE], [relG, FALSE]];
RETURN [Test[ModeMap[rep]][l, r, OpMap[op].map] = OpMap[op].sense]
END;
IntervalTest: PUBLIC PROCEDURE [l, r: Tree.Link, rep: Repr] RETURNS [BOOLEAN] =
BEGIN
InTest: ARRAY IntOp OF RECORD [lb, ub: RelOp] =
[[relG, relL], [relG, relLE], [relGE, relL], [relGE, relLE]];
subNode: Tree.Index = GetNode[r];
op: IntOp = tb[subNode].name;
RETURN [
RelTest[l, tb[subNode].son[1], InTest[op].lb, rep]
AND
RelTest[l, tb[subNode].son[2], InTest[op].ub, rep] ]
END;
Choose: PROCEDURE [list: Tree.Link, test: RelOp, rep: Repr] RETURNS [val: Tree.Link] =
BEGIN
started: BOOLEAN;
Item: Tree.Scan =
BEGIN
SELECT TRUE FROM
~started => BEGIN started ← TRUE; val ← t END;
RelTest[t, val, test, rep] => val ← t;
ENDCASE;
END;
started ← FALSE; ScanList[list, Item]; RETURN
END;
-- operations
MinSS: INTEGER = FIRST[INTEGER];
MaxSS: INTEGER = LAST[INTEGER];
TestSS: PROCEDURE [t1, t2: Tree.Link, op: RelOp] RETURNS [BOOLEAN] =
BEGIN
v1: INTEGER = TreeLiteralValue[t1];
v2: INTEGER = TreeLiteralValue[t2];
RETURN [SELECT op FROM
relE => v1 = v2,
relL => v1 < v2,
relG => v1 > v2,
ENDCASE => ERROR]
END;
UnarySS: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v: INTEGER;
v1: INTEGER = TreeLiteralValue[tb[node].son[1]];
SELECT tb[node].name FROM
uminus => IF v1 # MinSS THEN v ← -v1 ELSE GO TO Overflow;
abs =>
IF v1 # MinSS THEN v ← IF v1 < 0 THEN -v1 ELSE v1 ELSE GO TO Overflow;
ENDCASE => ERROR;
t ← MakeTreeLiteral[v]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← TRUE; t ← [subtree[node]];
Log.ErrorTree[overflow, t]
END;
END;
BinarySS: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v: INTEGER;
v1: INTEGER = TreeLiteralValue[tb[node].son[1]];
v2: INTEGER = TreeLiteralValue[tb[node].son[2]];
SELECT tb[node].name FROM
plus =>
IF (IF v1 >= 0 THEN v2 <= MaxSS-v1 ELSE v2 >= MinSS-v1)
THEN v ← v1 + v2
ELSE GO TO Overflow;
minus =>
IF (IF v1 >= 0 THEN v1-MaxSS <= v2 ELSE v1-MinSS >= v2)
THEN v ← v1 - v2
ELSE GO TO Overflow;
times =>
IF (SELECT TRUE FROM
(v1 > 0) AND (v2 > 0) => v2 <= MaxSS / v1,
(v1 > 0) AND (v2 < 0) => v2 >= MinSS / v1,
(v1 < 0) AND (v2 > 0) => v1 >= MinSS / v2,
(v1 < 0) AND (v2 < 0) =>
v1 # MinSS AND v2 # MinSS AND v2 >= MaxSS / v1,
ENDCASE => TRUE)
THEN v ← v1 * v2
ELSE GO TO Overflow;
div =>
IF v2 # 0 AND (v2 # -1 OR v1 # MinSS)
THEN v ← v1 / v2
ELSE GO TO Overflow;
mod =>
IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow;
ENDCASE => ERROR;
t ← MakeTreeLiteral[v]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← TRUE; t ← [subtree[node]];
Log.ErrorTree[overflow, t]
END;
END;
MaxSU: CARDINAL = LAST[CARDINAL];
TestSU: PROCEDURE [t1, t2: Tree.Link, op: RelOp] RETURNS [BOOLEAN] =
BEGIN
v1: CARDINAL = TreeLiteralValue[t1];
v2: CARDINAL = TreeLiteralValue[t2];
RETURN [SELECT op FROM
relE => v1 = v2,
relL => v1 < v2,
relG => v1 > v2,
ENDCASE => ERROR]
END;
UnarySU: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v1: CARDINAL = TreeLiteralValue[tb[node].son[1]];
SELECT tb[node].name FROM
uminus => IF v1 # 0 THEN GO TO Overflow;
abs => NULL;
ENDCASE => ERROR;
t ← MakeTreeLiteral[v1]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← FALSE; t ← [subtree[node]];
Log.ErrorTree[overflow, t];
END;
END;
BinarySU: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v: CARDINAL;
v1: CARDINAL = TreeLiteralValue[tb[node].son[1]];
v2: CARDINAL = TreeLiteralValue[tb[node].son[2]];
SELECT tb[node].name FROM
plus => IF v2 <= MaxSU-v1 THEN v ← v1 + v2 ELSE GO TO Overflow;
minus => IF v1 >= v2 THEN v ← v1 - v2 ELSE GO TO Overflow;
times =>
IF v1 = 0 OR v2 <= MaxSU/v1 THEN v ← v1 * v2 ELSE GO TO Overflow;
div => IF v2 # 0 THEN v ← v1 / v2 ELSE GO TO Overflow;
mod => IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow;
ENDCASE => ERROR;
t ← MakeTreeLiteral[v]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← FALSE; t ← [subtree[node]];
Log.ErrorTree[overflow, t];
END;
END;
MinLS: LONG INTEGER = FIRST[LONG INTEGER];
MaxLS: LONG INTEGER = LAST[LONG INTEGER];
TestLS: PROCEDURE [t1, t2: Tree.Link, op: RelOp] RETURNS [BOOLEAN] =
BEGIN
v1: LONG INTEGER = LongLiteralValue[t1];
v2: LONG INTEGER = LongLiteralValue[t2];
RETURN [SELECT op FROM
relE => v1 = v2,
relL => v1 < v2,
relG => v1 > v2,
ENDCASE => ERROR]
END;
UnaryLS: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v: LONG INTEGER;
v1: LONG INTEGER = LongLiteralValue[tb[node].son[1]];
SELECT tb[node].name FROM
uminus => IF v1 # MinLS THEN v ← -v1 ELSE GO TO Overflow;
abs =>
IF v1 # MinLS THEN v ← IF v1 < 0 THEN -v1 ELSE v1 ELSE GO TO Overflow;
ENDCASE => ERROR;
t ← MakeLongLiteral[v, tb[node].info]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← TRUE; t ← [subtree[node]];
Log.ErrorTree[overflow, t]
END;
END;
BinaryLS: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v: LONG INTEGER;
v1: LONG INTEGER = LongLiteralValue[tb[node].son[1]];
v2: LONG INTEGER = LongLiteralValue[tb[node].son[2]];
SELECT tb[node].name FROM
plus =>
IF (IF v1 >= 0 THEN v2 <= MaxLS-v1 ELSE v2 >= MinLS-v1)
THEN v ← v1 + v2
ELSE GO TO Overflow;
minus =>
IF (IF v1 >= 0 THEN v1-MaxLS <= v2 ELSE v1-MinLS >= v2)
THEN v ← v1 - v2
ELSE GO TO Overflow;
times =>
IF (SELECT TRUE FROM
(v1 > 0) AND (v2 > 0) => v2 <= MaxLS / v1,
(v1 > 0) AND (v2 < 0) => v2 >= MinLS / v1,
(v1 < 0) AND (v2 > 0) => v1 >= MinLS / v2,
(v1 < 0) AND (v2 < 0) =>
v1 # MinLS AND v2 # MinLS AND v2 >= MaxLS / v1,
ENDCASE => TRUE)
THEN v ← v1 * v2
ELSE GO TO Overflow;
div =>
IF v2 # 0 AND (v2 # -1 OR v1 # MinLS)
THEN v ← v1 / v2
ELSE GO TO Overflow;
mod =>
IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow;
ENDCASE => ERROR;
t ← MakeLongLiteral[v, tb[node].info]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← TRUE; t ← [subtree[node]];
Log.ErrorTree[overflow, t]
END;
END;
MaxLU: LONG CARDINAL = LAST[LONG CARDINAL];
TestLU: PROCEDURE [t1, t2: Tree.Link, op: RelOp] RETURNS [BOOLEAN] =
BEGIN
v1: LONG CARDINAL = LongLiteralValue[t1];
v2: LONG CARDINAL = LongLiteralValue[t2];
RETURN [SELECT op FROM
relE => v1 = v2,
relL => v1 < v2,
relG => v1 > v2,
ENDCASE => ERROR]
END;
UnaryLU: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v1: LONG CARDINAL = LongLiteralValue[tb[node].son[1]];
SELECT tb[node].name FROM
uminus => IF v1 # 0 THEN GO TO Overflow;
abs => NULL;
ENDCASE => ERROR;
t ← MakeLongLiteral[v1, tb[node].info]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← FALSE; t ← [subtree[node]];
Log.ErrorTree[overflow, t];
END;
END;
BinaryLU: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
v: LONG CARDINAL;
v1: LONG CARDINAL = LongLiteralValue[tb[node].son[1]];
v2: LONG CARDINAL = LongLiteralValue[tb[node].son[2]];
SELECT tb[node].name FROM
plus => IF v2 <= MaxLU-v1 THEN v ← v1 + v2 ELSE GO TO Overflow;
minus => IF v1 >= v2 THEN v ← v1 - v2 ELSE GO TO Overflow;
times =>
IF v1 = 0 OR v2 <= MaxLU/v1 THEN v ← v1 * v2 ELSE GO TO Overflow;
div => IF v2 # 0 THEN v ← v1 / v2 ELSE GO TO Overflow;
mod => IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow;
ENDCASE => ERROR;
t ← MakeLongLiteral[v, tb[node].info]; FreeNode[node];
EXITS
Overflow =>
BEGIN
tb[node].attr3 ← FALSE; t ← [subtree[node]];
Log.ErrorTree[overflow, t];
END;
END;
TestOther: PROCEDURE [t1, t2: Tree.Link, op: RelOp] RETURNS [BOOLEAN] =
BEGIN
RETURN [SELECT op FROM
relE => TreeLiteralDesc[t1] = TreeLiteralDesc[t2],
ENDCASE => ERROR]
END;
OpError: PROCEDURE [node: Tree.Index] RETURNS [t: Tree.Link] =
BEGIN
ERROR
END;
END.