DIRECTORY
Alloc: TYPE USING [Notifier],
Code: TYPE USING [codeptr, CodePassInconsistency],
CodeDefs:
TYPE
USING [
Base, CCIndex, CCNull, codeType, JumpCCIndex, JumpType,
RelativePC, TableCodeBytes],
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],
PrincOps:
TYPE
USING [
zJ6, zJ8, zJB, zJEB, zJEBB, zJEP, zJGB, zJGEB, zJLB, zJLEB, zJNEB, zJNEBB,
zJNEP, zJNZ4, zJNZB, zJUGB, zJUGEB, zJULB, zJULEB, zJW, zJZ4, zJZB];
DJumps:
PROGRAM
IMPORTS CPtr: Code, P5, P5F, PeepholeDefs
EXPORTS CodeDefs, P5F =
BEGIN
OPEN PeepholeDefs, OpCodeParams, CodeDefs;
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 PrincOps, 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;