
<<VarBasics.mesa>>
<<last edited by Sweet,  5-Aug-82 14:10:10>>
<<last edited by Satterthwaite, April 16, 1986 2:36:42 pm PST>>

DIRECTORY
Alloc: TYPE USING [Notifier],
Basics: TYPE USING [LongNumber],
Code: TYPE USING [CodeNotImplemented, curctxlvl],
CodeDefs: TYPE USING [
Base, BoVarIndex, BYTE, codeType, DataStackIndex, Lexeme, NullLex,
StackBackup, StackLocRec, VarComponent, VarIndex, VarNull, wordlength],
FOpCodes: TYPE USING [
qACD, qADC, qADD, qAMUL, qAND, qBLT, qBLTC, qBLTCL, qBLTL,
qDADD, qDIS, qLI, qLL, qLLK, qLP, qMUL, qR, qRC, qRCFS, qREC, qSHIFTSB],
LiteralOps: TYPE USING [FindDescriptor],
Literals: TYPE USING [Base, LTIndex, ltType],
P5: TYPE USING [MoveToCodeWord, WriteCodeWord],
P5L: TYPE USING [
AllLoaded, CopyToTemp, CopyVarItem, EasilyLoadable,
FieldOfVar, GenVarItem, LoadComponent, LoadVar, ModComponent,
LongVarAddress, OVarItem, ReleaseVarItem, ReusableCopies,
StoreVar, TOSComponent, TOSLex, VarAddressEasy, VarAlignment],
P5U: TYPE USING [Out0, Out1, RecordConstant],
PrincOps: TYPE USING [FieldDescriptor, framelink, localbase],
Stack: TYPE USING [
Above, Also, DataIndex, Forget, Load, Loc, Pop, TempStore, Top],
Symbols: TYPE USING [Base, ContextLevel, ctxType, lG, lZ, seType];

VarBasics: PROGRAM
IMPORTS CPtr: Code, LiteralOps, P5, P5U, P5L, Stack
EXPORTS P5L, CodeDefs =
BEGIN OPEN FOpCodes, CodeDefs, Symbols;

cb: CodeDefs.Base;
seb, ctxb: Symbols.Base;
ltb: Literals.Base;

VarBasicsNotify: PUBLIC Alloc.Notifier =
BEGIN  -- called by allocator whenever table area is repacked
seb _ base[Symbols.seType];
ctxb _ base[Symbols.ctxType];
cb _ base[codeType];
ltb _ base[Literals.ltType];
END;

AddrComponent: PUBLIC PROC [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];
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];
GenAdd[vv.delta];
RETURN [P5L.TOSComponent[1]]
END;
stack =>
IF vv.wd = 0 AND vv.bd = 0 THEN
BEGIN
loc: StackLocRec = Stack.Loc[vv.sti, var.wSize];
WITH ll: loc SELECT FROM
contig => WITH bb: ll.place SELECT FROM
frame => 
BEGIN
Stack.Forget[vv.sti, var.wSize];
RETURN [[wSize: 1, space: faddr[level: bb.tLevel, wd: bb.tOffset]]]
END;
ENDCASE;
ENDCASE;
END;
caddr => ERROR; -- nobody should be taking the address of a code address
ENDCASE; -- faddr, link, const, pdesc
<<put it in a temp, generate addr of temp>>
RETURN [AddrComponent[P5L.CopyToTemp[P5L.OVarItem[var]].var]]
END;

AddrForVar: PUBLIC PROC [r: VarIndex, codeOk: BOOL_FALSE]
RETURNS [avar: VarComponent] =
BEGIN
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 WITH vv: cc.base SELECT FROM
faddr => {vv.wd _ vv.wd + oo.wd; avar _ vv};
ENDCASE => 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: BOOL = LoadAddress[r, codeOk];
avar _ P5L.TOSComponent[IF long THEN 2 ELSE 1];
END;
END;

BaseComponent: PUBLIC PROC [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: PrincOps.framelink,
level: CPtr.curctxlvl]]];
P5U.Out1[qLL, PrincOps.framelink];
THROUGH (lvl..CPtr.curctxlvl) DO
P5U.Out1[qR, PrincOps.framelink - PrincOps.localbase];
ENDLOOP;
RETURN [P5L.TOSComponent[1]]
END;

GenAdd: PUBLIC PROC [delta: UNSPECIFIED, long: BOOL_FALSE] =
BEGIN
n: [1..2] = IF long THEN 2 ELSE 1;
Stack.Load[Stack.Top[n],n];
P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]];
P5U.Out0[IF long THEN qADC ELSE qADD];
END;

GenAnd: PUBLIC PROC [delta: UNSPECIFIED] =
BEGIN
P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]];
P5U.Out0[qAND];
END;

GenRFC: PUBLIC PROC [wd: CARDINAL, bd: [0..16), len: [1..16]] =
BEGIN
IF bd = 0 AND len = 16 THEN {
IF wd > BYTE.LAST THEN {GenAdd[wd-BYTE.LAST]; wd _ BYTE.LAST};
P5U.Out1[qRC, wd]}
ELSE {
IF wd > BYTE.LAST THEN {GenAdd[wd-BYTE.LAST]; wd _ BYTE.LAST};
P5U.Out1[qLI, 
LOOPHOLE[PrincOps.FieldDescriptor[offset: wd, posn: bd, size: len]]];
P5U.Out0[qRCFS]};
END;

GenShift: PUBLIC PROC [delta: UNSPECIFIED] =
BEGIN
IF INTEGER[delta] IN [-15..15] THEN 
P5U.Out1[qSHIFTSB, delta]
ELSE {
P5U.Out0[qDIS];
P5U.Out1[qLI, 0]};
END;

LoadAddress: PUBLIC PROC [r: VarIndex, codeOk: BOOL_FALSE] RETURNS [long: BOOL] =
BEGIN
bor: BoVarIndex;
base, offset: VarComponent;
owd: CARDINAL;
WITH cc: cb[r] SELECT FROM
o =>
BEGIN
avar: VarComponent _ AddrComponent[cc.var];
P5L.ReleaseVarItem[r];
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 _ Words[base.wSize, base.bSize] > 1;
WITH oo: offset SELECT FROM
frame =>
BEGIN
IF oo.level # lZ THEN ERROR CPtr.CodeNotImplemented;
owd _ oo.wd;
END;
code =>
BEGIN
IF ~codeOk OR long THEN ERROR;
owd _ oo.wd;
END;
ENDCASE => ERROR;
WITH vv: base SELECT FROM
faddr => IF vv.wd + owd IN BYTE THEN
BEGIN
vv.wd _ vv.wd + owd;
owd _ 0;
END;
ENDCASE;
P5L.LoadComponent[base];
IF owd # 0 THEN GenAdd[owd, long];
END;

LoadBoth: PUBLIC PROC [atC1, atC2: POINTER TO VarComponent, abelian: BOOL] =
BEGIN
[] _ LoadBothInternal[atC1, atC2, abelian];
END;

LoadBothInternal: PRIVATE PROC [atC1, atC2: POINTER TO VarComponent, abelian: BOOL] 
RETURNS [s1Size, s2Size: CARDINAL] =
BEGIN
c1: VarComponent _ atC1^;
c2: VarComponent _ atC2^;
c1Loaded, c2Loaded: BOOL _ 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 => {c1Depth _ depth; c1Loaded _ TRUE};
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 => {c2Depth _ depth; c2Loaded _ TRUE};
ENDCASE;
END;
ENDCASE;
BEGIN -- to set up loadBoth label
IF ~(c1Loaded OR c2Loaded) THEN GO TO loadBoth;
IF c1Loaded AND c2Loaded THEN 
SELECT TRUE FROM
(c1Depth = c2Size AND c2Depth = 0) => RETURN [c1Size, c2Size];
(abelian AND c2Depth = c1Size AND c1Depth = 0) => RETURN [c2Size, c1Size];
ENDCASE => GO TO loadBoth; -- considered unlikely
IF c1Loaded THEN
BEGIN
IF c1Depth # 0 THEN P5L.LoadComponent[c1];
P5L.LoadComponent[c2];
RETURN [c1Size, c2Size];
END
ELSE -- c2Loaded
BEGIN
IF c2Depth # 0 THEN {P5L.LoadComponent[c2]; c2 _ P5L.TOSComponent[c2Size]};
IF ~abelian AND (c1Size>1 OR c2Size>1) THEN c2 _ Stack.TempStore[c2Size];
P5L.LoadComponent[c1];
IF ~abelian THEN P5L.LoadComponent[c2];
IF abelian THEN RETURN[c2Size, c1Size] ELSE RETURN [c1Size, c2Size];
END;
EXITS
loadBoth => {P5L.LoadComponent[c1]; P5L.LoadComponent[c2]; RETURN [c1Size, c2Size]};
END;
END;

LoadSum: PUBLIC PROC [atB, atD: POINTER TO VarComponent] RETURNS [bpSize: [1..2]] =
BEGIN -- atB and atD are of size IN [1..2]
s1Size, s2Size: [1..2];
AddOp: ARRAY [1..2] OF ARRAY [1..2] OF BYTE = [
[FOpCodes.qADD, FOpCodes.qACD], [FOpCodes.qADC, FOpCodes.qDADD]];

[s1Size, s2Size] _ LoadBothInternal[atB, atD, TRUE];
P5U.Out0[AddOp[s1Size][s2Size]];
RETURN [MAX[s1Size, s2Size]];
END;

MakeBo: PUBLIC PROC [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: TRASH, offset: TRASH]]; -- set tag
WITH cc: cb[r] SELECT FROM
o => 
BEGIN
var: VarComponent _ cc.var;
vbSize: [0..16) = var.bSize;
vwSize: CARDINAL = var.wSize;
wS: CARDINAL = Words[vwSize, vbSize];
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: vwSize, space: frame[wd: vv.delta]];
RETURN
END;
linkup =>
BEGIN
cb[bor].base _ [wSize: 1, space: link[wd: vv.wd]];
cb[bor].offset _ [wSize: vwSize, space: frame[wd: vv.delta]];
RETURN
END;
code => cb[bor].offset _ [wSize: TRASH, bSize: TRASH, space: code[bd: vv.bd]];
frame => cb[bor].offset _ [wSize: TRASH, bSize: TRASH, space: frame[bd: vv.bd]];
stack => {
cb[bor].offset _ [wSize: TRASH, bSize: TRASH, space: frame[bd: vv.bd]];
var.wSize _ wS; var.bSize _ 0; vv.bd _ 0};
const =>
BEGIN
IF wS = 1 THEN { 
cb[bor].offset _ -- can't index packed in code anyway
[wSize: TRASH, bSize: TRASH, space: frame[bd: vv.bd]];
var.wSize _ wS; var.bSize _ 0; vv.bd _ 0}
ELSE
BEGIN -- wS = 2
const: ARRAY [0..1] OF CARDINAL _ [vv.d1, vv.d2];
lti: Literals.LTIndex = LiteralOps.FindDescriptor[DESCRIPTOR[const]].lti;
cb[bor].offset _ [wSize: TRASH, bSize: TRASH, space: code[bd: vv.bd]];
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]];
P5U.RecordConstant[ll.codeIndex, 2];
END;
var _ [wSize: 2, space: code[wd: ll.codeIndex]];
END;
ENDCASE => ERROR;
END;
END;
ENDCASE => ERROR;
cb[bor].base _ AddrComponent[var];
cb[bor].offset.wSize _ vwSize;
cb[bor].offset.bSize _ vbSize;
RETURN
END;
bdo => {disp _ cc.disp; base _ cc.base; offset _ cc.offset};
ind =>
BEGIN
eWords: CARDINAL;
base _ cc.base;
disp _ cc.index;
offset _ cc.offset;
WITH pp: cc SELECT FROM
packed => {P5L.ReleaseVarItem[bor]; RETURN [LOOPHOLE[VarNull]]};
notPacked => eWords _ pp.eWords;
ENDCASE;
IF eWords # 1 THEN
BEGIN
WITH vv: disp SELECT FROM
const =>
BEGIN
ld: Basics.LongNumber;
ld.lc _ CARDINAL[vv.d1].LONG * eWords.LONG;
vv.d1 _ ld.lowbits;
IF ld.highbits # 0 THEN {vv.wSize _ 2; vv.d2 _ ld.highbits};
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[qREC];
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: Basics.LongNumber;
owd: CARDINAL;
WITH oo: offset SELECT FROM
frame => owd _ oo.wd;
code => owd _ oo.wd;
ENDCASE => ERROR;
ld.lc _ owd.LONG + CARDINAL[vv.d1].LONG;
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 PROC [r: VarIndex, allowFields: BOOL _ FALSE]
RETURNS [var: VarComponent] =
BEGIN
wS: CARDINAL;
WITH cc: cb[r] SELECT FROM
o => {var _ cc.var; GO TO freer};
bo =>
BEGIN
WITH oo: cc.offset SELECT FROM
code =>
WITH bb: cc.base SELECT FROM
caddr => 
BEGIN
var _ [wSize: cc.offset.wSize, bSize: cc.offset.bSize,
space: code[wd: bb.wd + oo.wd, bd: oo.bd]];
GO TO freer;
END;
ENDCASE;
frame => 
WITH bb: cc.base SELECT FROM
faddr => SELECT bb.level FROM
lG, CPtr.curctxlvl => 
BEGIN
var _ [
wSize: cc.offset.wSize, bSize: cc.offset.bSize,
space: frame[level: bb.level, wd: bb.wd + oo.wd, bd: oo.bd]];
GO TO freer;
END;
ENDCASE;
frame => IF ~allowFields AND cc.base.bSize = 0
AND cc.base.wSize IN [1..2] AND cc.offset.bSize = 0
AND cc.offset.wSize = 1 AND oo.level = lZ THEN
BEGIN
var _ [
wSize: cc.offset.wSize, space: frameup[
level: bb.level, wd: bb.wd, pwSize: cc.base.wSize,
delta: oo.wd, immutable: bb.immutable]];
GO TO freer;
END;
link => IF ~allowFields AND cc.offset.bSize = 0
AND cc.offset.wSize IN [1..2] AND oo.level = lZ THEN
BEGIN
var _ [
wSize: cc.offset.wSize, space: linkup[wd: bb.wd, delta: oo.wd]];
GO TO freer;
END;
ENDCASE;
ENDCASE => ERROR;
wS _ Words[cc.offset.wSize, cc.offset.bSize];
END;
bdo => wS _ Words[cc.offset.wSize, cc.offset.bSize];
ind => wS _ Words[cc.offset.wSize, cc.offset.bSize];
ENDCASE;
IF wS > 2 THEN var _ P5L.CopyToTemp[r].var
ELSE {P5L.LoadVar[r]; var _ P5L.TOSComponent[wS]};
EXITS
freer => P5L.ReleaseVarItem[r];
END;

VarVarAssign: PUBLIC PROC [to, from: VarIndex, isexp: BOOL] 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: BOOL _ FALSE;
tLevel: Symbols.ContextLevel _ Symbols.lZ;
backup1, backup2: StackBackup _ [none[]];
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: DataStackIndex = Stack.DataIndex[vv.sti];
backup1 _ cb[vsti].backup;
IF wS = 2 THEN
BEGIN
nsti: DataStackIndex = Stack.DataIndex[Stack.Above[vsti]];
backup2 _ cb[nsti].backup;
END;
END;
ENDCASE;
ENDCASE;
IF backup1.where = none OR (wS = 2 AND backup2.where = none) THEN
WITH cb[to] SELECT FROM
o => WITH vv: var SELECT FROM
frame => IF vv.bSize = 0 AND vv.bd = 0 THEN
BEGIN
level: Symbols.ContextLevel = vv.level;
SELECT level FROM
lG, CPtr.curctxlvl => {
backup1 _ [frame[tLevel: level, tOffset: vv.wd]];
backup2 _ [frame[tLevel: level, tOffset: vv.wd+1]]};
ENDCASE;
END;
ENDCASE;
ENDCASE;
END;
P5L.ReleaseVarItem[from];
P5L.StoreVar[to];
IF isexp THEN
BEGIN
P5U.Out0[qREC]; IF backup1.where # none THEN Stack.Also[backup1];
IF wS = 2 THEN {
P5U.Out0[qREC]; IF backup2.where # none THEN Stack.Also[backup2]};
l _ P5L.TOSLex[wS];
END;
END
ELSE IF P5L.AllLoaded[from] THEN
BEGIN -- large thing, all on stack
IF isexp THEN 
BEGIN
tr: VarIndex;
[first: to, next: tr] _ P5L.ReusableCopies[to, store, FALSE];
l _ [bdo[tr]];
END;
P5L.StoreVar[to];
END
ELSE IF bSize = 0 THEN
BEGIN
fromCode: BOOL;
longDest: BOOL _ P5L.LongVarAddress[to];
longSource: BOOL _ P5L.LongVarAddress[from];
sourceAddr, destAddr: VarComponent;
destInTemp: BOOL _ FALSE;
expBase: {unknown, source, dest} _ unknown;
BltOp: ARRAY BOOL OF ARRAY BOOL OF BYTE =
[[qBLT, qBLTL], [qBLTC, qBLTCL]];
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  isexp AND longDest = longSource AND P5L.VarAddressEasy[from]
AND ~P5L.VarAddressEasy[to] THEN expBase _ source;
sourceAddr _ 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];
IF ~fromCode THEN P5U.Out0[qLP];
END
ELSE P5L.LoadComponent[sourceAddr];
P5U.Out1[qLI, wSize];
destAddr _ 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: TRASH]];
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;
[first: fMain, next: fNub] _ P5L.ReusableCopies[from, store, TRUE];
[first: tMain, next: tNub] _ P5L.ReusableCopies[to, store, FALSE];
IF tbd = 0 THEN
BEGIN
tr: VarIndex _ tMain;
tMain _ tNub; tNub _ tr;
tr _ fMain; fMain _ fNub; fNub _ fMain;
END;
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 PROC [w, b: CARDINAL] RETURNS [CARDINAL] =
BEGIN
RETURN [w + ((b+15)/16)];
END;

END.

