-- file DJumps.mesa
-- last modified by Sweet, 30-Oct-81 14:36:52
-- last modified by JGS, 13-Nov-81 12:33:56
-- last modified by Satterthwaite, December 16, 1982 9:12 am
DIRECTORY
Alloc: TYPE USING [Notifier],
Code: TYPE USING [codeptr, CodePassInconsistency],
CodeDefs: TYPE USING [
Base, CCIndex, CCNull, codeType, JumpCCIndex, JumpType,
RelativePC, TableCodeBytes],
Mopcodes: TYPE USING [
zJ6, zJ8, zJB, zJEB, zJEBB, zJEP, zJGB, zJGEB, zJLB, zJLEB, zJNEB, zJNEBB,
zJNEP, zJNZ4, zJNZB, zJUGB, zJUGEB, zJULB, zJULEB, zJW, zJZ4, zJZB],
OpCodeParams: TYPE USING [
BYTE, HB, MaxBBJumps, MaxFBJumps, zJn, zJNZn, zJZn],
P5: TYPE USING [C0, C1, C1W, C2],
P5F: TYPE USING [StartIndex],
PeepholeDefs: TYPE USING [CJump, PackPair];
DJumps: PROGRAM
IMPORTS CPtr: Code, P5, P5F, PeepholeDefs
EXPORTS CodeDefs, P5F =
BEGIN
OPEN PeepholeDefs, OpCodeParams, CodeDefs;
-- imported definitions
BYTE: TYPE = OpCodeParams.BYTE;
cb: CodeDefs.Base; -- code base (local copy)
DJumpsNotify: PUBLIC Alloc.Notifier =
BEGIN -- called by allocator whenever table area is repacked
cb ← base[codeType];
END;
BindJump: PUBLIC PROC [min, max: INTEGER, c: JumpCCIndex]
RETURNS [bindable: BOOL ← TRUE] =
BEGIN -- compute size of jump instruction(s)
-- max and min are counts of the number of bytes between the
-- jump and the label.
t: JumpType = cb[c].jtype;
js: [0..7];
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 min = max THEN
SELECT min FROM
1, 2, 3, 5, 7 => js ← 1;
4, 6 => js ← 2;
IN [-MaxBBJumps..MaxFBJumps-2] => js ← 2;
ENDCASE => js ← 3
ELSE SELECT TRUE FROM
(min >= 1 AND max <= 3) => js ← 1;
(min > 7 AND max <= MaxFBJumps-2) => js ← 2;
max IN [-MaxBBJumps..0] => js ← 2;
min NOT IN [-MaxBBJumps..MaxFBJumps-2] => js ← 3;
ENDCASE => bindable ← FALSE;
JumpLIO => js ← 3;
JumpCA => SELECT TRUE FROM
max IN [-MaxBBJumps..MaxFBJumps-2] => js ← 2;
min NOT IN [-MaxBBJumps..MaxFBJumps-2] => js ← 3;
ENDCASE => bindable ← FALSE;
BYTEJumpN, BYTEJumpE => SELECT TRUE FROM
(cb[c].jparam IN HB AND min >= 2 AND max <= 17) => js ← 2;
max IN [-MaxBBJumps..MaxFBJumps-3] => js ← 3;
min NOT IN [-MaxBBJumps..MaxFBJumps-3] =>
js ← IF cb[c].jparam IN HB THEN 5 ELSE 6;
ENDCASE => bindable ← FALSE;
ZJumpE => SELECT TRUE FROM
(min >= 2 AND max <= 3) => js ← 1;
(min > 3 AND max <= MaxFBJumps-2) => js ← 2;
max IN [-MaxBBJumps..2) => js ← 2;
min NOT IN [-MaxBBJumps..MaxFBJumps-2] => js ← 4;
ENDCASE => bindable ← FALSE;
ZJumpN => SELECT TRUE FROM
(min >= 2 AND max <= 3) => js ← 1;
(min > 3 AND max <= MaxFBJumps-2) => js ← 2;
max IN [-MaxBBJumps..2) => js ← 2;
min NOT IN [-MaxBBJumps..MaxFBJumps-2] => js ← 4;
ENDCASE => bindable ← FALSE;
ENDCASE => SELECT TRUE FROM
max IN [-MaxBBJumps..MaxFBJumps-2] => js ← 2;
min NOT IN [-MaxBBJumps..MaxFBJumps-2] => js ← 5;
ENDCASE => bindable ← FALSE;
IF bindable THEN {cb[c].fixedup ← TRUE; cb[c].jsize ← js};
RETURN
END;
CodeJump: PUBLIC PROC [nbytes: INTEGER, c: JumpCCIndex] =
BEGIN -- code all jump instruction(s)
OPEN Mopcodes, OpCodeParams;
l: [0..7] = cb[c].jsize;
forward: BOOL = cb[c].forward;
t: JumpType;
RelJumpOps: ARRAY JumpType[JumpE..ZJumpN] OF BYTE = [
zJEB, zJNEB, zJLB, zJGEB, zJGB, zJLEB, zJULB, zJUGEB, zJUGB, zJULEB,
zJZB, zJNZB];
jDist: INTEGER ← IF ~forward THEN -nbytes ELSE nbytes+l;
IF l > 3 THEN jDist ← jDist + 3 - l;
-- Computing dist copes with the fact that the parameter to a jump
-- instruction is added to the byte pc of the first byte of the instruction
-- nbytes is the number of bytes between the jump and its label
CPtr.codeptr ← c;
t ← cb[c].jtype;
SELECT t FROM
Jump, JumpA, JumpCA =>
SELECT l FROM
1 =>
BEGIN
SELECT jDist FROM
2, 3, 4 => P5.C0[zJn+jDist-2];
6 => P5.C0[zJ6];
8 => P5.C0[zJ8];
ENDCASE => ERROR;
END;
2 =>
BEGIN
P5.C1[zJB, jDist];
END;
ENDCASE =>
BEGIN
P5.C1W[zJW, jDist];
END;
ZJumpE, ZJumpN =>
SELECT l FROM
1 =>
BEGIN
P5.C0[(IF t=ZJumpE THEN zJZn ELSE zJNZn)+jDist-3];
END;
2 =>
BEGIN
P5.C1[(IF t = ZJumpE THEN zJZB ELSE zJNZB), jDist];
END;
ENDCASE =>
BEGIN
P5.C0[(IF t = ZJumpE THEN zJNZ4 ELSE zJZ4)];
P5.C1W[zJW, jDist];
END;
BYTEJumpE =>
SELECT l FROM
2 => P5.C1[zJEP, PackPair[cb[c].jparam, jDist-4]];
3 => P5.C2[zJEBB, cb[c].jparam, jDist];
5 => {P5.C1[zJNEP, PackPair[cb[c].jparam, 5-4]]; P5.C1W[zJW, jDist]};
6 => {P5.C2[zJNEBB, cb[c].jparam, 6]; P5.C1W[zJW, jDist]};
ENDCASE => SIGNAL CPtr.CodePassInconsistency;
BYTEJumpN =>
SELECT l FROM
2 => P5.C1[zJNEP, PackPair[cb[c].jparam, jDist-4]];
3 => P5.C2[zJNEBB, cb[c].jparam, jDist];
5 => {P5.C1[zJEP, PackPair[cb[c].jparam, 5-4]]; P5.C1W[zJW, jDist]};
6 => {P5.C2[zJEBB, cb[c].jparam, 6]; P5.C1W[zJW, jDist]};
ENDCASE => SIGNAL CPtr.CodePassInconsistency;
JumpC => NULL;
JumpLIO => NULL; -- later fixed up by OutBinary
ENDCASE =>
SELECT l FROM
2 =>
BEGIN
P5.C1[RelJumpOps[t], jDist];
END;
ENDCASE =>
BEGIN
P5.C1[RelJumpOps[CJump[t]], 5];
P5.C1W[zJW, jDist];
END;
cb[c].completed ← TRUE;
cb[c].jsize ← 0; -- so it doesn't have to be ignored in ComputeJumpDistance
RETURN
END;
dMinMax: ARRAY {unconditional, equal, byte, relational, enable} OF
PACKED ARRAY BOOL OF RECORD [min,max: [0..15]] ← [
unconditional: [[2,3], [1,3]], -- (backward, forward)
equal: [[2,4], [1,4]], -- (backward, forward)
byte: [[3,4], [2,4]], -- (backward, forward)
relational: [[2,5], [2,5]], -- (backward, forward)
enable: [[3,3], [3,3]]];
FillInPCEstimates: PUBLIC PROC =
BEGIN
min, max: RelativePC ← 0;
FOR k: CCIndex ← P5F.StartIndex, cb[k].flink UNTIL k = CCNull DO
WITH cc:cb[k] SELECT FROM
code =>
BEGIN
t: CARDINAL = cc.isize;
min ← min + t;
max ← max + t;
END;
jump => IF cc.jtype # JumpC THEN
BEGIN
IF ~cc.fixedup THEN
BEGIN
dMin, dMax: [0..15];
[dMin,dMax] ← dMinMax[(SELECT cc.jtype FROM
Jump, JumpA, JumpCA => unconditional,
JumpE, JumpN, ZJumpE, ZJumpN => equal,
JumpEnable => enable,
BYTEJumpN => byte,
ENDCASE => relational)][cc.forward];
IF cc.jtype = BYTEJumpN OR cc.jtype = BYTEJumpE THEN
dMax ← dMax + (IF cc.jparam IN HB THEN 1 ELSE 2);
IF ~cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
min ← min+dMin; max ← max+dMax;
IF cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
END
ELSE IF ~cc.completed THEN
BEGIN
t: CARDINAL = cc.jsize;
IF ~cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
min ← min + t;
max ← max + t;
IF cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
END;
END;
label => {cc.minPC ← min; cc.maxPC ← max};
other => WITH cc SELECT FROM
table =>
BEGIN
min ← min + TableCodeBytes;
max ← max + TableCodeBytes;
END;
ENDCASE;
ENDCASE;
ENDLOOP;
END;
END.