
<<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 1, 1985 3:58:56 pm PST>>

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;

<<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 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;

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.

