-- VarBasics.mesa Edited by Sweet, January 15, 1980 5:10 PM
DIRECTORY
AltoDefs: FROM "altodefs" USING [BYTE, wordlength],
Code: FROM "code" USING [CodeNotImplemented, curctxlvl, dStar, stking],
CodeDefs: FROM "codedefs",
ControlDefs: FROM "controldefs" USING [FieldDescriptor,
framelink, localbase],
FOpCodes: FROM "fopcodes" USING [qADD, qAMUL, qAND, qBLT,
qBLTC, qBLTL, qDADD, qLI, qLL, qLLK, qLP, qMUL, qNOOP,
qPUSH, qR, qRFC, qSHIFT],
InlineDefs: FROM "inlinedefs" USING [LongNumber],
LiteralOps: FROM "literalops" USING [FindDescriptor],
Literals: FROM "literals" USING [LTIndex, ltType],
P5: FROM "p5" USING [MoveToCodeWord, WriteCodeWord],
P5L: FROM "p5l" USING [
AllLoaded, AddrComponent, AddrForVar, CopyToTemp, CopyVarItem,
EasilyLoadable, FieldOfVar, GenAdd, GenVarItem, LoadAddress, LoadBoth,
LoadComponent, LoadVar, LongVarAddress, ModComponent,
OVarItem, ReleaseVarItem, ReusableCopies, StoreVar, TOSComponent, TOSLex,
VarAddressEasy, VarAlignment, VarStackWords, Words],
P5U: FROM "p5u" USING [Out0, Out1, Out2],
Stack: FROM "stack" USING [Above, Also, Forget, Loc, Pop, Require, TempStore],
Symbols: FROM "symbols" USING [ContextLevel, ctxType, lG, lZ, seType],
Table: FROM "table" USING [Base, Notifier],
Tree: FROM "tree" USING [treeType];
VarBasics: PROGRAM
IMPORTS LCPtr: Code, LiteralOps, P5, P5U, P5L, Stack
EXPORTS P5L, CodeDefs =
BEGIN OPEN FOpCodes, CodeDefs, Symbols;
CPtr: POINTER TO FRAME [Code] = LCPtr;
wordlength: CARDINAL = AltoDefs.wordlength;
BYTE: TYPE = AltoDefs.BYTE;
cb, seb, ctxb, ltb: Table.Base;
VarBasicsNotify: PUBLIC Table.Notifier =
BEGIN -- called by allocator whenever table area is repacked
seb ← base[Symbols.seType];
ctxb ← base[Symbols.ctxType];
cb ← base[Tree.treeType];
ltb ← base[Literals.ltType];
RETURN
END;
AddrComponent: PUBLIC PROCEDURE [var: VarComponent] RETURNS [avar: VarComponent] =
BEGIN
WITH vv: var SELECT FROM
code => RETURN [[wSize: 1, space: caddr[wd: vv.wd]]];
frame => RETURN [[wSize: 1, space: faddr[level: vv.level, wd: vv.wd]]];
frameup =>
BEGIN
base: VarComponent =
[wSize: vv.pwSize, space:
frame[wd: vv.wd, level: vv.level, immutable: vv.immutable]];
IF vv.delta = 0 THEN RETURN[base];
P5L.LoadComponent[base];
P5L.GenAdd[vv.delta, base.wSize > 1];
RETURN[P5L.TOSComponent[base.wSize]];
END;
linkup =>
BEGIN
IF vv.delta = 0 THEN RETURN [[wSize: 1, space: link[wd: vv.wd]]];
P5U.Out1[qLLK, vv.wd];
P5L.GenAdd[vv.delta];
RETURN [P5L.TOSComponent[1]];
END;
stack =>
BEGIN
loc: StackLocRec = Stack.Loc[vv.sti, var.wSize];
WITH loc SELECT FROM
inTemp =>
BEGIN
Stack.Forget[vv.sti, var.wSize];
RETURN [[wSize: 1, space: faddr[level: tLevel, wd: tOffset]]];
END;
ENDCASE;
END;
caddr => ERROR; -- nobody should be taking the address of a code address
ENDCASE; -- faddr, link, const, pdesc
BEGIN -- put it in a temp, generate addr of temp
tvar: VarComponent ← P5L.CopyToTemp[P5L.OVarItem[var]].var;
RETURN [P5L.AddrComponent[tvar]];
END;
END;
AddrForVar: PUBLIC PROCEDURE [r: VarIndex, codeOk: BOOLEAN ← FALSE] RETURNS [avar: VarComponent] =
BEGIN
BEGIN -- to set up "loadIt" label
WITH cc: cb[r] SELECT FROM
o =>
BEGIN
IF ~codeOk AND cc.var.tag = code THEN ERROR;
avar ← AddrComponent[cc.var];
END;
bo =>
BEGIN
WITH oo: cc.offset SELECT FROM
frame => IF oo.level = lZ AND oo.wd = 0 THEN avar ← cc.base
ELSE GO TO loadIt;
code => IF codeOk AND oo.wd = 0 THEN avar ← cc.base
ELSE GO TO loadIt;
ENDCASE => ERROR;
END;
ENDCASE => GO TO loadIt;
P5L.ReleaseVarItem[r];
EXITS
loadIt =>
BEGIN
long: BOOLEAN ← P5L.LoadAddress[r, codeOk];
avar ← P5L.TOSComponent[IF long THEN 2 ELSE 1];
END;
END;
END;
BaseComponent: PUBLIC PROCEDURE [lvl: ContextLevel] RETURNS [VarComponent] =
BEGIN
IF lvl >= CPtr.curctxlvl THEN ERROR;
IF lvl + 1 = CPtr.curctxlvl THEN
RETURN [[wSize: 1, space: frame[
immutable: TRUE,
wd: ControlDefs.framelink,
level: CPtr.curctxlvl]]];
P5U.Out1[qLL, ControlDefs.framelink];
THROUGH (lvl..CPtr.curctxlvl) DO
P5U.Out1[qR, ControlDefs.framelink - ControlDefs.localbase];
ENDLOOP;
RETURN[P5L.TOSComponent[1]];
END;
GenAdd: PUBLIC PROCEDURE [delta: UNSPECIFIED, long: BOOLEAN ← FALSE] =
BEGIN
P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]];
IF long THEN P5U.Out1[qLI, 0];
P5U.Out0[IF long THEN qDADD ELSE qADD];
END;
GenAnd: PUBLIC PROCEDURE [delta: UNSPECIFIED] =
BEGIN
P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]];
P5U.Out0[qAND];
END;
GenRFC: PUBLIC PROCEDURE [wd: CARDINAL, bd: [0..16), len: [1..16]] =
BEGIN
IF wd > LAST[BYTE] THEN
BEGIN
GenAdd[wd-LAST[BYTE]];
wd ← LAST[BYTE];
END;
P5U.Out2[qRFC, wd,
LOOPHOLE[ControlDefs.FieldDescriptor[offset: 0, posn: bd, size: len]]];
END;
GenShift: PUBLIC PROCEDURE [delta: UNSPECIFIED] =
BEGIN
P5U.Out1[qLI, delta];
P5U.Out0[qSHIFT];
END;
LoadAddress: PUBLIC PROCEDURE [r: VarIndex, codeOk: BOOLEAN ← FALSE]
RETURNS [long: BOOLEAN] =
BEGIN
bor: BoVarIndex;
base, offset: VarComponent;
WITH cc: cb[r] SELECT FROM
o =>
BEGIN
avar: VarComponent ← AddrComponent[cc.var];
IF avar.tag = caddr AND ~codeOk THEN ERROR;
P5L.LoadComponent[avar];
RETURN [FALSE];
END;
ENDCASE;
bor ← MakeBo[r];
IF bor = VarNull THEN SIGNAL CPtr.CodeNotImplemented;
base ← cb[bor].base; offset ← cb[bor].offset;
P5L.ReleaseVarItem[bor];
long ← P5L.Words[base.wSize, base.bSize] > 1;
P5L.LoadComponent[base];
WITH oo: offset SELECT FROM
frame =>
BEGIN
IF oo.level # lZ THEN ERROR CPtr.CodeNotImplemented;
IF oo.wd # 0 THEN
BEGIN
P5U.Out1[qLI, oo.wd];
IF long THEN P5U.Out1[qLI, 0]; -- lengthen
P5U.Out0[IF long THEN qDADD ELSE qADD];
END;
END;
code =>
BEGIN
IF ~codeOk OR long THEN ERROR;
IF oo.wd # 0 THEN GenAdd[oo.wd];
END;
ENDCASE => ERROR;
END;
LoadBoth: PUBLIC PROCEDURE [atC1, atC2: POINTER TO VarComponent, abelian: BOOLEAN] =
BEGIN
c1: VarComponent ← atC1↑;
c2: VarComponent ← atC2↑;
c1Loaded, c2Loaded: BOOLEAN ← FALSE;
c1Depth, c2Depth: CARDINAL;
c1Size: CARDINAL = Words[c1.wSize, c1.bSize];
c2Size: CARDINAL = Words[c2.wSize, c2.bSize];
WITH cc: c1 SELECT FROM
stack => IF cc.bd = 0 AND c1.bSize = 0 THEN
BEGIN
loc: StackLocRec = Stack.Loc[cc.sti, c1Size];
WITH loc SELECT FROM
onStack =>
BEGIN c1Depth ← depth; c1Loaded ← TRUE; END;
ENDCASE;
END;
ENDCASE;
WITH cc: c2 SELECT FROM
stack => IF cc.bd = 0 AND c2.bSize = 0 THEN
BEGIN
loc: StackLocRec = Stack.Loc[cc.sti, c2Size];
WITH loc SELECT FROM
onStack =>
BEGIN c2Depth ← depth; c2Loaded ← TRUE; END;
ENDCASE;
END;
ENDCASE;
BEGIN -- to set up loadBoth label
IF ~(c1Loaded OR c2Loaded) THEN GO TO loadBoth;
IF c1Loaded AND c2Loaded THEN
IF (c1Depth = c2Size AND c2Depth = 0) OR
(abelian AND c2Depth = c1Size AND c1Depth = 0) THEN RETURN
ELSE GO TO loadBoth; -- considered unlikely
IF c1Loaded THEN
BEGIN
IF c1Depth # 0 THEN P5L.LoadComponent[c1];
P5L.LoadComponent[c2];
END
ELSE -- c2Loaded
BEGIN
IF c2Depth # 0 THEN P5L.LoadComponent[c2];
IF ~abelian AND (c1Size>1 OR c2Size>1) THEN
c2 ← Stack.TempStore[c2Size];
P5L.LoadComponent[c1];
IF ~abelian THEN P5L.LoadComponent[c2];
END;
EXITS
loadBoth =>
BEGIN
P5L.LoadComponent[c1];
P5L.LoadComponent[c2];
END;
END;
END;
LoadSum: PUBLIC PROCEDURE [atB, atD: POINTER TO VarComponent]
RETURNS [bpSize: [1..2]] =
BEGIN
base, disp: VarComponent;
dpSize: [1..2];
alreadyOn: CARDINAL ← 0;
BDCommute: PROCEDURE =
BEGIN
t: VarComponent = base;
i: CARDINAL ← bpSize;
base ← disp; disp ← t;
bpSize ← dpSize; dpSize ← i;
END;
base ← atB↑; disp ← atD↑;
bpSize ← Words[base.wSize, base.bSize];
dpSize ← Words[disp.wSize, disp.bSize];
WITH base SELECT FROM
stack => alreadyOn ← alreadyOn + bpSize;
ENDCASE;
WITH disp SELECT FROM
stack => alreadyOn ← alreadyOn + dpSize;
ENDCASE;
IF (bpSize = 2 OR dpSize = 2) AND ~CPtr.dStar THEN
Stack.Require[alreadyOn]; -- could dump what was on
BEGIN -- to set up "different" exit label
SELECT bpSize FROM
>dpSize => GO TO different;
<dpSize => BEGIN BDCommute[]; GO TO different END;
ENDCASE => P5L.LoadBoth[@base, @disp, TRUE];
EXITS
different =>
BEGIN
P5L.LoadComponent[disp];
P5U.Out1[qLI, 0]; --lengthen disp
disp ← P5L.TOSComponent[2];
P5L.LoadBoth[@base, @disp, TRUE];
END;
END;
P5U.Out0[IF bpSize = 1 THEN qADD ELSE qDADD];
RETURN
END;
MakeBo: PUBLIC PROCEDURE [r: VarIndex] RETURNS [bor: BoVarIndex] =
BEGIN
base, disp, offset: VarComponent;
bpSize: [1..2];
WITH cb[r] SELECT FROM
bo => RETURN [LOOPHOLE[r]];
ENDCASE;
bor ← LOOPHOLE[P5L.GenVarItem[bo]];
cb[bor] ← [body: bo[base: NULL, offset: NULL]]; -- set tag
WITH cc: cb[r] SELECT FROM
o =>
BEGIN
var: VarComponent ← cc.var;
P5L.ReleaseVarItem[r];
WITH vv: var SELECT FROM
frameup =>
BEGIN
cb[bor].base ←
[wSize: vv.pwSize, space:
frame[wd: vv.wd, level: vv.level, immutable: vv.immutable]];
cb[bor].offset ← [wSize: var.wSize, space: frame[wd: vv.delta]];
RETURN
END;
linkup =>
BEGIN
cb[bor].base ← [wSize: 1, space: link[wd: vv.wd]];
cb[bor].offset ← [wSize: var.wSize, space: frame[wd: vv.delta]];
RETURN
END;
code => cb[bor].offset ←
[wSize: NULL, bSize: NULL, space: code[bd: vv.bd]];
frame => cb[bor].offset ←
[wSize: NULL, bSize: NULL, space: frame[bd: vv.bd]];
stack => cb[bor].offset ←
[wSize: NULL, bSize: NULL, space: frame[bd: vv.bd]];
const =>
BEGIN
wS: CARDINAL = P5L.Words[var.wSize, var.bSize];
IF wS = 1 THEN
cb[bor].offset ← -- can't index packed in code anyway
[wSize: NULL, bSize: NULL, space: frame[bd: vv.bd]]
ELSE
BEGIN -- wS = 2
const: ARRAY [0..1] OF CARDINAL ← [vv.d1, vv.d2];
lti: Literals.LTIndex;
cb[bor].offset ←
[wSize: NULL, bSize: NULL, space: code[bd: vv.bd]];
lti ← LiteralOps.FindDescriptor[DESCRIPTOR[const]];
WITH ll: ltb[lti] SELECT FROM
long =>
BEGIN
IF ll.codeIndex = 0 THEN
BEGIN
ll.codeIndex ← P5.MoveToCodeWord[];
P5.WriteCodeWord[const[0]];
P5.WriteCodeWord[const[1]];
END;
var ← [wSize: 2, space: code[wd: ll.codeIndex]];
END;
ENDCASE => ERROR;
END;
END;
ENDCASE => ERROR;
cb[bor].base ← P5L.AddrComponent[var];
cb[bor].offset.wSize ← var.wSize;
cb[bor].offset.bSize ← var.bSize;
RETURN
END;
bdo =>
BEGIN
disp ← cc.disp;
base ← cc.base;
offset ← cc.offset;
END;
ind =>
BEGIN
eWords: CARDINAL;
base ← cc.base;
disp ← cc.index;
offset ← cc.offset;
WITH pp: cc SELECT FROM
packed =>
BEGIN P5L.ReleaseVarItem[bor]; RETURN [LOOPHOLE[VarNull]] END;
notPacked => eWords ← pp.eWords;
ENDCASE;
IF eWords # 1 THEN
BEGIN
WITH vv: disp SELECT FROM
const =>
BEGIN
ld: InlineDefs.LongNumber;
ld.lc ← LONG[CARDINAL[vv.d1]] * LONG[eWords];
vv.d1 ← ld.lowbits;
IF ld.highbits # 0 THEN
BEGIN vv.wSize ← 2; vv.d2 ← ld.highbits; END;
GO TO const;
END;
ENDCASE;
P5L.LoadComponent[disp];
P5U.Out1[qLI, eWords];
IF cc.simple THEN
BEGIN
P5U.Out0[qMUL];
disp ← P5L.TOSComponent[1];
END
ELSE
BEGIN
P5U.Out0[qAMUL];
P5U.Out0[qPUSH];
disp ← P5L.TOSComponent[2];
END;
EXITS
const => NULL;
END;
END;
ENDCASE;
P5L.ReleaseVarItem[r];
WITH vv: disp SELECT FROM
const => IF vv.wSize = 1 AND vv.bSize = 0 THEN
BEGIN
ld: InlineDefs.LongNumber;
owd: CARDINAL;
WITH oo: offset SELECT FROM
frame => owd ← oo.wd;
code => owd ← oo.wd;
ENDCASE => ERROR;
ld.lc ← LONG[owd] + LONG[CARDINAL[vv.d1]];
IF ld.highbits = 0 THEN
BEGIN
P5L.ModComponent[var: @offset, wd: vv.d1];
cb[bor].base ← base;
cb[bor].offset ← offset;
RETURN
END;
END;
ENDCASE;
bpSize ← LoadSum[@base, @disp];
cb[bor].base ← P5L.TOSComponent[bpSize];
cb[bor].offset ← offset;
END;
MakeComponent: PUBLIC PROCEDURE [r: VarIndex, allowFields: BOOLEAN ← FALSE]
RETURNS [var: VarComponent] =
BEGIN
wS: CARDINAL;
WITH cb[r] SELECT FROM
o => RETURN[var];
bo =>
BEGIN
WITH oo: offset SELECT FROM
code =>
WITH bb: base SELECT FROM
caddr =>
BEGIN
var ← [wSize: offset.wSize, bSize: offset.bSize,
space: code[wd: bb.wd + oo.wd, bd: oo.bd]];
GO TO freer;
END;
ENDCASE;
frame =>
WITH bb: base SELECT FROM
faddr => SELECT bb.level FROM
lG, CPtr.curctxlvl =>
BEGIN
var ← [
wSize: offset.wSize, bSize: offset.bSize,
space: frame[
level: bb.level, wd: bb.wd + oo.wd, bd: oo.bd]];
GO TO freer;
END;
ENDCASE;
frame => IF ~allowFields AND base.bSize = 0
AND base.wSize IN [1..2] AND offset.bSize = 0
AND offset.wSize = 1 AND oo.level = lZ THEN
BEGIN
var ← [
wSize: offset.wSize, space: frameup[
level: bb.level, wd: bb.wd, pwSize: base.wSize,
delta: oo.wd, immutable: bb.immutable]];
GO TO freer;
END;
link => IF ~allowFields AND offset.bSize = 0
AND offset.wSize IN [1..2] AND oo.level = lZ THEN
BEGIN
var ← [
wSize: offset.wSize, space: linkup[
wd: bb.wd, delta: oo.wd]];
GO TO freer;
END;
ENDCASE;
ENDCASE => ERROR;
wS ← Words[offset.wSize, offset.bSize];
END;
bdo => wS ← Words[offset.wSize, offset.bSize];
ind => wS ← Words[offset.wSize, offset.bSize];
ENDCASE;
IF wS > 2 THEN var ← P5L.CopyToTemp[r].var
ELSE BEGIN P5L.LoadVar[r]; var ← P5L.TOSComponent[wS]; END;
EXITS
freer => P5L.ReleaseVarItem[r];
END;
VarVarAssign: PUBLIC PROCEDURE [to, from: VarIndex, isexp: BOOLEAN]
RETURNS [l: Lexeme] =
BEGIN
bSize, tbd: [0..wordlength);
wSize, wS: CARDINAL;
trashOnStack: CARDINAL ← 0;
l ← NullLex;
[bd: tbd, bSize: bSize, wSize: wSize] ←
P5L.VarAlignment[to, store];
wS ← Words[wSize, bSize];
WITH cc: cb[from] SELECT FROM
o => WITH vv: cc.var SELECT FROM
stack => IF vv.wd # 0 THEN
IF isexp THEN
BEGIN
P5L.LoadVar[from]; -- causing from to be freed
from ← P5L.OVarItem[P5L.TOSComponent[wS]];
END
ELSE
BEGIN
tvar: VarComponent;
trashOnStack ← vv.wd;
vv.wd ← 0;
tvar ← cc.var; -- to avoid passing address of chunk
P5L.ModComponent[var: @tvar, wd: trashOnStack];
cc.var ← tvar;
END;
ENDCASE;
ENDCASE;
IF wS <= 2 THEN
BEGIN -- it's 2 words at most
alsoLink: BOOLEAN ← FALSE;
tOffset: TempAddr;
tLevel: Symbols.ContextLevel ← Symbols.lZ;
IF ~P5L.AllLoaded[from] THEN -- anything above it is part of "to"
BEGIN
P5L.LoadVar[from];
from ← P5L.OVarItem[P5L.TOSComponent[wS]];
END;
IF isexp THEN
BEGIN -- locate a backup site for stack model after PUSH
-- "from" is a stack o varitem, see if it is alsotemp
-- otherwise, see if "to" is a friendly frame loc (doesn't
-- have to be immutable in this case
WITH cb[from] SELECT FROM
o => WITH vv: var SELECT FROM
stack =>
BEGIN
vsti: StackIndex = vv.sti;
WITH sv: cb[vsti] SELECT FROM
onStack =>
BEGIN
IF sv.alsoLink OR sv.tLevel # lZ THEN
BEGIN
nsti: StackIndex;
alsoLink ← sv.alsoLink;
tOffset ← sv.tOffset;
tLevel ← sv.tLevel;
IF wS = 1 THEN GO TO foundOne;
IF tLevel # lZ THEN
BEGIN
nsti ← Stack.Above[vsti];
WITH sv2: cb[nsti] SELECT FROM
onStack =>
IF sv2.tLevel = tLevel AND
sv2.tOffset = tOffset+1 THEN
GO TO foundOne;
ENDCASE;
END;
alsoLink ← FALSE; tLevel ← lZ;
END;
END;
ENDCASE;
END;
ENDCASE;
ENDCASE;
WITH cb[to] SELECT FROM
o => WITH vv: var SELECT FROM
link =>
BEGIN alsoLink ← TRUE; tLevel ← vv.wd; END;
frame => IF vv.bSize = 0 AND vv.bd = 0 THEN
BEGIN
level: Symbols.ContextLevel = vv.level;
SELECT level FROM
lG, CPtr.curctxlvl =>
BEGIN tLevel ← level; tOffset ← vv.wd; END;
ENDCASE;
END;
ENDCASE;
ENDCASE;
EXITS
foundOne => NULL;
END;
P5L.ReleaseVarItem[from];
P5L.StoreVar[to];
IF isexp THEN
BEGIN
THROUGH [0..wS) DO P5U.Out0[qPUSH]; ENDLOOP;
IF (alsoLink OR tLevel # lZ) AND CPtr.stking THEN
Stack.Also[n: wS, inLink: alsoLink, tOffset: tOffset, tLevel: tLevel];
l ← P5L.TOSLex[wS];
END;
END
ELSE IF P5L.AllLoaded[from] THEN
BEGIN -- large thing, all on stack
IF isexp THEN
BEGIN
tr: VarIndex;
[to, tr] ← P5L.ReusableCopies[to, store, FALSE];
l ← [bdo[tr]];
END;
P5L.StoreVar[to];
END
ELSE IF bSize = 0 THEN
BEGIN
fromCode: BOOLEAN;
longDest: BOOLEAN ← P5L.LongVarAddress[to];
longSource: BOOLEAN ← P5L.LongVarAddress[from];
sourceAddr, destAddr: VarComponent;
expBase: {unknown, source, dest} ← unknown;
BltOp: ARRAY BOOLEAN OF ARRAY BOOLEAN OF BYTE =
[[qBLT, qBLTL], [qBLTC, qNOOP]]; -- peephole will choke on BLTCL
-- but it shouldn't be generated, anyway
WITH ff: cb[from] SELECT FROM
o => fromCode ← ff.var.tag = code;
bo => fromCode ← ff.offset.tag = code;
bdo => fromCode ← ff.offset.tag = code;
ind => fromCode ← ff.offset.tag = code;
ENDCASE => ERROR;
IF fromCode AND longDest THEN
BEGIN
tvar: VarComponent = P5L.CopyToTemp[from].var;
[] ← VarVarAssign[to: to, from: P5L.OVarItem[tvar], isexp: FALSE];
IF isexp THEN l ← [bdo[P5L.OVarItem[tvar]]];
RETURN -- trashOnStack = 0
END;
IF ~CPtr.dStar OR longSource OR longDest THEN
Stack.Require[P5L.VarStackWords[from]+ P5L.VarStackWords[to]];
IF isexp AND longDest = longSource AND P5L.VarAddressEasy[from]
AND ~P5L.VarAddressEasy[to] THEN expBase ← source;
sourceAddr ← P5L.AddrForVar[r: from, codeOk: TRUE];
IF longDest AND ~longSource THEN
BEGIN
IF isexp THEN
BEGIN
sourceAddr ← P5L.EasilyLoadable[sourceAddr, store];
expBase ← source;
END;
P5L.LoadComponent[sourceAddr];
P5U.Out0[qLP];
END
ELSE P5L.LoadComponent[sourceAddr];
P5U.Out1[qLI, wSize];
destAddr ← P5L.AddrForVar[to];
IF longSource AND ~longDest THEN
BEGIN
IF isexp THEN
BEGIN
destAddr ← P5L.EasilyLoadable[destAddr, store];
expBase ← dest;
END;
P5L.LoadComponent[destAddr];
P5U.Out0[qLP];
longDest ← TRUE;
END
ELSE
BEGIN
IF isexp AND expBase = unknown THEN
BEGIN
destAddr ← P5L.EasilyLoadable[destAddr, store];
expBase ← dest;
END;
P5L.LoadComponent[destAddr];
END;
P5U.Out0[BltOp[fromCode][longDest]];
IF isexp THEN
BEGIN
tr: BoVarIndex = LOOPHOLE[P5L.GenVarItem[bo]];
SELECT expBase FROM
source => NULL;
dest => sourceAddr ← destAddr;
ENDCASE => ERROR;
cb[tr] ← [body: bo[base: sourceAddr, offset: NULL]];
IF expBase = source AND fromCode THEN
cb[tr].offset ← [wSize: wSize, space: code[wd: 0]]
ELSE
cb[tr].offset ← [wSize: wSize, space: frame[wd: 0]];
l ← [bdo[tr]];
END;
END
ELSE
BEGIN
-- vars are ragged on at most one end; i.e., if wSize # 0 and bSize # 0
-- then bd = 0 or bd+bSize = wordlength, also bd # 0 implies bSize # 0
fMain, fNub: VarIndex;
tMain, tNub: VarIndex;
[fMain, fNub] ← P5L.ReusableCopies[from, store];
[tMain, tNub] ← P5L.ReusableCopies[to, store];
IF isexp THEN
l ← [bdo[P5L.CopyVarItem[tMain]]]; -- has been rendered reusable
IF tbd = 0 THEN
BEGIN
P5L.FieldOfVar[r: fMain, wSize: wSize];
P5L.FieldOfVar[r: fNub, wd: wSize, bSize: bSize];
P5L.FieldOfVar[r: tMain, wSize: wSize];
P5L.FieldOfVar[r: tNub, wd: wSize, bSize: bSize];
[] ← VarVarAssign[to: tNub, from: fNub, isexp: FALSE];
[] ← VarVarAssign[to: tMain, from: fMain, isexp: FALSE];
END
ELSE
BEGIN
IF tbd + bSize # wordlength THEN ERROR;
P5L.FieldOfVar[r: fMain, wSize: wSize, bd: bSize];
P5L.FieldOfVar[r: fNub, bSize: bSize];
P5L.FieldOfVar[r: tMain, wSize: wSize, bd: bSize];
P5L.FieldOfVar[r: tNub, bSize: bSize];
[] ← VarVarAssign[to: tMain, from: fMain, isexp: FALSE];
[] ← VarVarAssign[to: tNub, from: fNub, isexp: FALSE];
END;
END;
THROUGH [0..trashOnStack) DO Stack.Pop[]; ENDLOOP;
END;
Words: PUBLIC PROCEDURE [w: CARDINAL, b: [0..wordlength)]
RETURNS [CARDINAL] =
BEGIN
RETURN [w + CARDINAL[b+15]/16];
END;
END.