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