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