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