-- file: PeepholeU.mesa, edited by Sweet on February 12, 1979  10:30 AM

DIRECTORY
  Code: FROM "code" USING [codeptr],
  P5U: FROM "p5u" USING [AllocCodeCCItem, DeleteCell, ParamCount],
  CodeDefs: FROM "codedefs" USING [CCIndex, CCNull, CodeCCIndex, CodeCCNull],
  ControlDefs: FROM "controldefs" USING [FieldDescriptor],
  FOpCodes: FROM "fopcodes" USING [qGADRB, qLADRB, qLG, qLI, qLL, qNOOP, qRIG, qRIL, qRR],
  InlineDefs: FROM "inlinedefs" USING [BITAND, BITOR, BITSHIFT],
  Mopcodes: FROM "mopcodes" USING [zLIB, zLIN1, zLINB, zLINI, zLIW],
  OpCodeParams: FROM "opcodeparams" USING [BYTE, LoadImmediateSlots, LocalHB, zLIn],
  OpTableDefs: FROM "optabledefs" USING [instaligned, instlength],
  P5: FROM "p5" USING [NumberOfParams, P5Error],
  PeepholeDefs: FROM "peepholedefs" USING [JumpPeepState, PeepState],
  Table: FROM "table" USING [Base, Notifier],
  Tree: FROM "tree" USING [treeType];

PeepholeU: PROGRAM
  IMPORTS CPtr: Code, InlineDefs, P5U, OpTableDefs, P5
  EXPORTS CodeDefs, P5, PeepholeDefs =
  PUBLIC BEGIN OPEN OpCodeParams, CodeDefs, PeepholeDefs;

  -- imported definitions

  BYTE: TYPE = OpCodeParams.BYTE;
  qNOOP: BYTE = FOpCodes.qNOOP;


  cb: Table.Base;		-- code base (local copy)

  PeepholeUNotify: Table.Notifier =
    BEGIN  -- called by allocator whenever table area is repacked
    cb ← base[Tree.treeType];
    RETURN
    END;

  sourceIndex: CARDINAL;

  SetSourceIndex: PROCEDURE [c: CARDINAL] =
    BEGIN sourceIndex ← c END;

  GenRealInst: BOOLEAN;

  SetRealInst: PROCEDURE [b: BOOLEAN] =
    BEGIN GenRealInst ← b END;


  HalfByteLocal: PROCEDURE [c: CCIndex] RETURNS [BOOLEAN] =
    BEGIN
    IF c = CCNull THEN RETURN [FALSE];
    WITH cb[c] SELECT FROM
      code => RETURN[inst = FOpCodes.qLL AND parameters[1] IN LocalHB];
      ENDCASE => RETURN [FALSE]
    END;

  LoadInst: PROCEDURE [c: CCIndex] RETURNS [BOOLEAN] =
    BEGIN OPEN FOpCodes;
    IF c = CCNull THEN RETURN[FALSE];
    WITH cb[c] SELECT FROM
      code => RETURN[~realinst AND (SELECT inst FROM
	qLI, qLL, qLG, qRIL, qRIG, qLADRB, qGADRB, qRR => TRUE,
	ENDCASE => FALSE)];
      ENDCASE => RETURN[FALSE]
    END;


  PackPair: PROCEDURE [l,r: [0..16)] RETURNS [w: WORD] =
    BEGIN OPEN InlineDefs;
    w ← BITSHIFT[l, 4];
    w ← BITOR[w, BITAND[r, 17B]];
    RETURN
    END;

  UnpackPair: PROCEDURE [w: WORD] RETURNS [l,r: [0..16)] =
    BEGIN OPEN InlineDefs;
    l ← BITAND[BITSHIFT[w, -4], 17B];
    r ← BITAND[w, 17B];
    RETURN
    END;

  UnpackFD: PROCEDURE [d: ControlDefs.FieldDescriptor] RETURNS [p,s: CARDINAL] =
    BEGIN
    [posn: p, size: s] ← d;
    RETURN
    END;


  InitParametersABC: PROCEDURE [p: POINTER TO PeepState] =
    BEGIN -- p.c is initialized and p.c # CCNull and cb[p.c].cctag = code
    OPEN p;
    i: CARDINAL;

    aInst ← bInst ← cInst ← qNOOP;
    aMin ← bMin ← cMin ← FALSE;
    a ← b ← CodeCCNull;
    IF ~(GenRealInst OR ~cb[c].realinst) THEN RETURN;
    FillInC[p];
    IF (b←LOOPHOLE[cb[c].blink, CodeCCIndex]) = CCNull THEN RETURN;
    WITH cb[LOOPHOLE[b, CCIndex]] SELECT FROM
      code =>
       IF GenRealInst OR ~realinst THEN
	BEGIN
	bInst ← inst;
	bMin ← minimalStack;
	bP ← [0,0,0];
	FOR i IN [1..P5U.ParamCount[b]] DO bP[i] ← parameters[i] ENDLOOP;
	END;
      ENDCASE;
    IF (a←LOOPHOLE[cb[b].blink, CodeCCIndex]) = CCNull THEN RETURN;
    WITH cb[LOOPHOLE[a, CCIndex]] SELECT FROM
      code =>
       IF GenRealInst OR ~realinst THEN
	BEGIN
	aInst ← inst;
	aMin ← minimalStack;
	aP ← [0,0,0];
	FOR i IN [1..P5U.ParamCount[a]] DO aP[i] ← parameters[i] ENDLOOP;
	END;
      ENDCASE;
    END;

  InitParametersBC: PROCEDURE [p: POINTER TO PeepState] =
    BEGIN -- p.c is initialized and p.c # CCNull and cb[p.c].cctag = code
    OPEN p;
    i: CARDINAL;

    aInst ← bInst ← cInst ← qNOOP;
    aMin ← bMin ← cMin ← FALSE;
    a ← b ← CodeCCNull;
    IF ~(GenRealInst OR ~cb[c].realinst) THEN RETURN;
    FillInC[p];
    IF (b←LOOPHOLE[cb[c].blink, CodeCCIndex]) = CCNull THEN RETURN;
    WITH cb[LOOPHOLE[b, CCIndex]] SELECT FROM
      code =>
       IF GenRealInst OR ~realinst THEN
	BEGIN
	bInst ← inst;
	bMin ← minimalStack;
	bP ← [0,0,0];
	FOR i IN [1..P5U.ParamCount[b]] DO bP[i] ← parameters[i] ENDLOOP;
	END;
      ENDCASE;
    END;

  InitParametersC: PROCEDURE [p: POINTER TO PeepState] =
    BEGIN -- p.c is initialized and p.c # CCNull and cb[p.c].cctag = code
    OPEN p;

    aInst ← bInst ← cInst ← qNOOP;
    aMin ← bMin ← cMin ← FALSE;
    a ← b ← CodeCCNull;
    IF ~(GenRealInst OR ~cb[c].realinst) THEN RETURN;
    FillInC[p];
    END;

  CondFillInC: PRIVATE PROCEDURE [p: POINTER TO PeepState] =
    BEGIN OPEN p;
    IF GenRealInst OR ~cb[c].realinst THEN FillInC[p]
    ELSE
      BEGIN
      aInst ← bInst ← cInst ← qNOOP;
      aMin ← bMin ← cMin ← FALSE;
      a ← b ← CodeCCNull;
      END;
    END; 

  FillInC: PRIVATE PROCEDURE [p: POINTER TO PeepState] =
    BEGIN -- p.c is initialized and p.c # CCNull and cb[p.c].cctag = code
    OPEN p;
    i: CARDINAL;

    CPtr.codeptr ← c;
    sourceIndex ← cb[c].sourcefileindex;
    cInst ← cb[c].inst;
    cMin ← cb[c].minimalStack;
    cP ← [0,0,0];
    FOR i IN [1..P5U.ParamCount[c]] DO cP[i] ← cb[c].parameters[i] ENDLOOP;
    END;

  InitJParametersBC: PROCEDURE [p: POINTER TO JumpPeepState] =
    BEGIN -- p.c is initialized and p.c # CCNull and cb[p.c].cctag = jump
    OPEN p;
    i: CARDINAL;

    bInst ← cInst ← qNOOP;
    bMin ← cMin ← FALSE;
    b ← CodeCCNull;
    IF (b←LOOPHOLE[cb[c].blink, CodeCCIndex]) = CCNull THEN RETURN;
    WITH cb[LOOPHOLE[b, CCIndex]] SELECT FROM
      code =>
	BEGIN
	bP ← [0,0,0];
	IF ~(GenRealInst OR ~cb[b].realinst) THEN 
	  BEGIN
	  bInst ← qNOOP;
	  bMin ← FALSE;
	  b ← CodeCCNull;
	  RETURN;
	  END;
	bInst ← inst;
	bMin ← minimalStack;
	FOR i IN [1..P5U.ParamCount[b]] DO bP[i] ← parameters[i] ENDLOOP;
	END;
      ENDCASE;
    END;

  SlidePeepState2: PROCEDURE [p: POINTER TO PeepState, ci: CodeCCIndex] =
    BEGIN OPEN p;
    a ← b; aMin ← bMin; aP ← bP; aInst ← bInst;
    b ← c; bMin ← cMin; bP ← cP; bInst ← cInst;
    c ← ci; CondFillInC[p];
    END;

  SlidePeepState1: PROCEDURE [p: POINTER TO PeepState, ci: CodeCCIndex] =
    BEGIN OPEN p;
    b ← c; bMin ← cMin; bP ← cP; bInst ← cInst;
    c ← ci; CondFillInC[p];
    END;

  LoadConstant: PROCEDURE [c: UNSPECIFIED] =
    BEGIN
    OPEN Mopcodes;
    ic: INTEGER;
    IF ~GenRealInst THEN
      BEGIN C1[FOpCodes.qLI, c]; RETURN END;
    ic ← LOOPHOLE[c];
    SELECT ic FROM
      IN LoadImmediateSlots => C0[zLIn+ic];
      -1 => C0[zLIN1];
      100000B => C0[zLINI];
      IN BYTE => C1[zLIB, ic];
      ENDCASE => 
	IF -ic IN BYTE THEN
	  C1[zLINB, InlineDefs.BITAND[ic,377B]]
	ELSE C1W[zLIW, ic];
    RETURN
    END;

  MC0: PROCEDURE [i: BYTE, minimal: BOOLEAN] =
    BEGIN -- outputs an parameter-less instruction
    c: CodeCCIndex;

    IF InstParamCount[i] # 0 THEN P5.P5Error[961];
    c ← PeepAllocCodeCCItem[i,0];
    cb[c].inst ← i;
    cb[c].minimalStack ← minimal;
    RETURN
    END;


  C0: PROCEDURE [i: BYTE] =
    BEGIN -- outputs an parameter-less instruction
    c: CodeCCIndex;

    IF InstParamCount[i] # 0 THEN P5.P5Error[962];
    c ← PeepAllocCodeCCItem[i,0];
    cb[c].inst ← i;
    RETURN
    END;


  C1: PROCEDURE [i: BYTE, p1: WORD] =
    BEGIN -- outputs a one-parameter instruction
    c: CodeCCIndex;

    c ← PeepAllocCodeCCItem[i,1];
    cb[c].inst ← i;
    cb[c].parameters[1] ← p1;
    RETURN
    END;


  C1W: PROCEDURE [i: BYTE, p1: WORD] =
    BEGIN -- outputs a one-parameter(two-byte-param) instruction
    c: CodeCCIndex;

    c ← PeepAllocCodeCCItem[i,2];
    cb[c].inst ← i;
    cb[c].parameters[1] ← InlineDefs.BITSHIFT[p1, -8];
    cb[c].parameters[2] ← InlineDefs.BITAND[p1, 377B];
    RETURN
    END;


  C2: PROCEDURE [i: BYTE, p1, p2: WORD] =
    BEGIN -- outputs a two-parameter instruction
    c: CodeCCIndex;

    c ← PeepAllocCodeCCItem[i,2];
    cb[c].inst ← i;
    cb[c].parameters[1] ← p1;
    cb[c].parameters[2] ← p2;
    RETURN
    END;


  C3: PROCEDURE [i: BYTE, p1, p2, p3: WORD] =
    BEGIN -- outputs a three-parameter instruction
    c: CodeCCIndex;

    c ← PeepAllocCodeCCItem[i,3];
    cb[c].inst ← i;
    cb[c].parameters[1] ← p1;
    cb[c].parameters[2] ← p2;
    cb[c].parameters[3] ← p3;
    RETURN
    END;


  InstParamCount: PROCEDURE [i: BYTE] RETURNS [CARDINAL] =
    BEGIN
    RETURN[IF GenRealInst THEN OpTableDefs.instlength[i]-1 ELSE P5.NumberOfParams[i]]
    END;

  PeepAllocCodeCCItem: PROCEDURE [i: BYTE, n: [0..3]] RETURNS [c: CodeCCIndex] =
    BEGIN
    IF InstParamCount[i] # n THEN P5.P5Error[963];
    c ← P5U.AllocCodeCCItem[n];
    cb[c].realinst ← GenRealInst;
    cb[c].sourcefileindex ← sourceIndex;
    IF GenRealInst THEN
      BEGIN
      cb[c].isize ← n+1;
      cb[c].aligned ← OpTableDefs.instaligned[i];
      END;
    RETURN
    END;

  Delete2: PROCEDURE [a,b: CCIndex] =
    BEGIN P5U.DeleteCell[a]; P5U.DeleteCell[b]; RETURN END;

  Delete3: PROCEDURE [a,b,c: CCIndex] =
    BEGIN P5U.DeleteCell[a]; P5U.DeleteCell[b]; P5U.DeleteCell[c]; RETURN END;


  END...