-- file AJumps.mesa
-- last modified by Sweet, March 20, 1979 4:52 PM
DIRECTORY
AltoDefs: FROM "altodefs" USING [BYTE],
Code: FROM "code" USING [codeptr],
CodeDefs: FROM "codedefs" USING [CCIndex, CCNull, JumpCCIndex, JumpType, RelativePC],
OpCodeParams: FROM "opcodeparams" USING [MaxBBJumps, MaxFBJumps, MaxFIAJumps, MaxFICJumps],
P5F: FROM "p5f" USING [CodeJumpDist, StartIndex],
Table: FROM "table" USING [Base, Notifier],
Tree: FROM "tree" USING [treeType];
AJumps: PROGRAM
IMPORTS CPtr: Code, P5F
EXPORTS CodeDefs, P5F =
BEGIN
OPEN OpCodeParams, CodeDefs;
-- imported definitions
BYTE: TYPE = AltoDefs.BYTE;
cb: Table.Base; -- code base (local copy)
AJumpsNotify: PUBLIC Table.Notifier =
BEGIN -- called by allocator whenever table area is repacked
cb ← base[Tree.treeType];
RETURN
END;
BindJump: PUBLIC PROCEDURE [min, max: INTEGER, c: JumpCCIndex] RETURNS [bindable: BOOLEAN] =
BEGIN -- compute size of jump instruction(s)
-- max and min are counts of the number of bytes between the
-- jump and the label. in particular max does not allow for
-- a possible pad on this jump (if backward).
t: JumpType;
js: [0..7];
bindable ← TRUE;
t ← cb[c].jtype;
IF t = JumpC THEN
BEGIN -- "bound" by OutBinary
cb[c].fixedup ← TRUE;
cb[c].completed ← TRUE;
RETURN
END;
IF ~cb[c].forward THEN BEGIN max ← -max; min ← -min END;
SELECT t FROM
Jump, JumpA =>
IF max IN [1..MaxFIAJumps] THEN js ← 1
ELSE IF max IN (MaxFIAJumps..MaxFBJumps) AND min > MaxFIAJumps THEN js ← 2
ELSE IF max IN (-(MaxBBJumps-1)..0] THEN js ← 2
ELSE IF min ~IN (-(MaxBBJumps-1)..MaxFBJumps) THEN js ← 3
ELSE bindable ← FALSE;
JumpE, JumpN =>
IF max IN [1..MaxFICJumps] THEN js ← 1
ELSE IF max IN (MaxFICJumps..MaxFBJumps) AND min > MaxFICJumps THEN js ← 2
ELSE IF max IN (-(MaxBBJumps-1)..0] THEN js ← 2
ELSE IF min ~IN (-(MaxBBJumps-1)..MaxFBJumps) THEN js ← 4
ELSE bindable ← FALSE;
JumpCA =>
IF max IN (-(MaxBBJumps-1)..MaxFBJumps) THEN js ← 2
ELSE IF min ~IN (-(MaxBBJumps-1)..MaxFBJumps) THEN js ← 3
ELSE bindable ← FALSE;
ENDCASE =>
IF max IN (-(MaxBBJumps-1)..MaxFBJumps) THEN js ← 2
ELSE IF min ~IN (-(MaxBBJumps-1)..MaxFBJumps) THEN js ← 6
ELSE bindable ← FALSE;
IF bindable THEN BEGIN cb[c].fixedup ← TRUE; cb[c].jsize ← js END;
RETURN
END;
CodeJump: PUBLIC PROCEDURE [nbytes: INTEGER, c: JumpCCIndex] =
BEGIN -- code all jump instruction(s)
forward: BOOLEAN;
dist: INTEGER;
pad: [0..1];
l: [0..7];
CPtr.codeptr ← c;
l ← cb[c].jsize;
forward ← cb[c].forward;
pad ← cb[c].pad;
-- The next statement copes with the fact that the parameter to a jump
-- instruction is added to the byte pc of the last byte of the instruction
-- nbytes is the number of bytes between the jump and its label
dist ← IF ~forward THEN 1-nbytes-l-pad
ELSE nbytes+1;
P5F.CodeJumpDist[dist, l, pad, c, FALSE];
END;
dMinMax: ARRAY {unconditional, equal, relational} OF
ARRAY [0..2] OF PACKED ARRAY BOOLEAN OF RECORD [min,max: [0..15]] ←
[ [[[2,4],[1,4]], -- unconditional, parity 0 (backward, forward)
[[3,3],[1,3]], -- unconditional, parity 1 (backward, forward)
[[2,4],[1,4]]], -- unconditional, parity 2 (backward, forward)
[[[2,4],[1,4]], -- equal, parity 0 (backward, forward)
[[3,5],[1,5]], -- equal, parity 1 (backward, forward)
[[2,5],[1,5]]], -- equal, parity 2 (backward, forward)
[[[2,6],[2,6]], -- relational, parity 0 (backward, forward)
[[3,7],[3,7]], -- relational, parity 1 (backward, forward)
[[2,7],[2,7]]]]; -- relational, parity 2 (backward, forward)
FillInPCEstimates: PUBLIC PROCEDURE =
BEGIN
k: CCIndex;
t: CARDINAL;
min, max: RelativePC;
parity: [0..2] ← 0;
dMin, dMax: [0..15];
min ← max ← 0;
FOR k ← P5F.StartIndex, cb[k].flink UNTIL k = CCNull DO
WITH cc:cb[k] SELECT FROM
code =>
BEGIN
t ← cc.isize;
IF cc.aligned THEN
BEGIN
IF parity = 2 THEN max ← max + 1
ELSE IF (parity+t) MOD 2 # 0 THEN t ← t + 1;
parity ← 0;
END
ELSE IF parity # 2 THEN parity ← (parity+t) MOD 2;
min ← min + t;
max ← max + t;
END;
jump => IF cc.jtype # JumpC THEN
BEGIN
IF ~cc.fixedup THEN
BEGIN
[dMin,dMax] ← dMinMax[(SELECT cc.jtype FROM
Jump,JumpA,JumpCA => unconditional,
JumpE,JumpN => equal,
ENDCASE => relational)][parity][cc.forward];
IF ~cc.forward THEN
BEGIN cc.minPC ← min; cc.maxPC ← max; END;
min ← min+dMin; max ← max+dMax;
IF cc.forward THEN
BEGIN cc.minPC ← min; cc.maxPC ← max; END;
parity ← (SELECT cc.jtype FROM
Jump,JumpA,JumpCA => 2,
JumpE,JumpN => IF cc.forward AND parity # 1 THEN 2 ELSE 0,
ENDCASE => 0);
END
ELSE IF ~cc.completed THEN
BEGIN
deltamax: CARDINAL ← 0;
t ← cc.jsize;
IF t = 1 THEN
BEGIN IF parity # 2 THEN parity ← (parity+1) MOD 2 END
ELSE
BEGIN
IF parity = 2 THEN deltamax ← 1
ELSE IF (parity+t) MOD 2 # 0 THEN t ← t + 1;
parity ← 0;
END;
IF ~cc.forward THEN
BEGIN cc.minPC ← min; cc.maxPC ← max; END;
min ← min + t;
max ← max + deltamax + t;
IF cc.forward THEN
BEGIN cc.minPC ← min; cc.maxPC ← max; END;
END;
END;
label =>
BEGIN cc.minPC ← min; cc.maxPC ← max; END;
other => WITH cc SELECT FROM
table =>
BEGIN
deltamax: CARDINAL ← 0;
t ← tablecodebytes;
IF parity = 2 THEN deltamax ← 1
ELSE IF (parity+t) MOD 2 # 0 THEN t ← t + 1;
parity ← 0;
min ← min + t;
max ← max + deltamax + t;
END;
ENDCASE;
ENDCASE;
ENDLOOP;
RETURN
END;
END..