-- file: PeepholeA.mesa
-- last edited by Sweet on  7-Sep-82 11:08:01
-- last edited by Satterthwaite on December 16, 1982 9:45 am

DIRECTORY
  Alloc: TYPE USING [Notifier],
  Code: TYPE USING [CodeNotImplemented],
  CodeDefs: TYPE USING [
    Base, CCIndex, CCNull, codeType, JumpCCIndex, JumpType],
  FOpCodes: TYPE USING [
    qADD, qAND, qDADD, qDB, qDBS, qDDUP, qDEXCH, qDMUL, qDUP,
    qEFC, qEXCH, qLG, qIOR, qLGD, qLL, qLLD, qLKB, qLLK, qMUL, qNULL,
    qPL, qPLD, qPS, qPSD, qPSDL, qPSF, qPSL, qPSLF, qR, qRD, qRDL,
    qREC, qREC2, qRF, qRGDI, qRGDIL, qRGI, qRGIF, qRGIL, qRGILF,
    qRKDI, qRKI, qRL, qRLF, qRLDI, qRLDIL, qRLI, qRLIF, qRLIL, qRLILF,
    qSG, qSGD, qSL, qSLD, qSUB, qW, qWD, qWDL, qWF, qWGDI, qWGDIL,
    qWGI, qWGIF, qWGIL, qWGILF,qWL, qWLDI, qWLDIL, qWLF, qWLI,
    qWLIF, qWLIL, qWLILF, qWS, qWSD, qWSDL, qWSF, qWSL, qWSLF, qXOR],
  OpCodeParams: TYPE USING [
    BYTE, GlobalHB, HB, LocalBase, LocalHB, RiImplemented],
  P5: TYPE USING [C0, C1, C2, C3, LoadConstant],
  P5U: TYPE USING [DeleteCell],
  PeepholeDefs: TYPE USING [
    CommuteCells, DblLoadInst, Delete2, InitParameters, LoadInst, NextInteresting,
    PeepState, PrevInteresting, SlidePeepState2, start];

PeepholeA: PROGRAM
    IMPORTS CPtr: Code, P5, P5U, PeepholeDefs
    EXPORTS PeepholeDefs =
  BEGIN OPEN PeepholeDefs, OpCodeParams, CodeDefs;

  -- imported definitions

  BYTE: TYPE = OpCodeParams.BYTE;

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


  PeepholeANotify: PUBLIC Alloc.Notifier =
    BEGIN  -- called by allocator whenever table area is repacked
    cb ← base[codeType];
    END;

  Peep2: PUBLIC PROC =
    BEGIN -- discover short magic
    OPEN FOpCodes;
    ci: CCIndex;
    next: CCIndex ← start;
    state: PeepState;
    canSlide: BOOL ← FALSE;
    UNTIL (ci ← next) = CCNull DO
      next ← NextInteresting[ci];
      WITH cb[ci] SELECT FROM
	code =>
	  BEGIN OPEN state;
	  IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]]
	  ELSE InitParameters[@state, LOOPHOLE[ci], abc];
	  canSlide ← FALSE;
	  SELECT cInst FROM
	    -- discover family members from sequences
	    qR =>
	      IF cP[1] IN HB THEN
		SELECT bInst FROM
		  qLL =>
		    IF -- RiImplemented[read][local][short][single] AND 
		    bP[1] IN LocalHB THEN 
		      {P5.C2[qRLI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLG =>
		    IF -- RiImplemented[read][global][short][single] AND 
		    bP[1] IN GlobalHB THEN 
		      {P5.C2[qRGI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLLK =>
		    IF cP[1] = 0 THEN {P5.C1[qRKI, bP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  ENDCASE => canSlide ← TRUE;
	    qW =>
	      IF cP[1] IN HB THEN
		SELECT bInst FROM
		  qLL =>
		    IF -- RiImplemented[write][local][short][single] AND 
		    bP[1] IN LocalHB THEN 
		      {P5.C2[qWLI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLG =>
		    IF -- RiImplemented[write][global][short][single] AND 
		    bP[1] IN GlobalHB THEN 
		      {P5.C2[qWGI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  ENDCASE => canSlide ← TRUE;
	    qRD =>
	      IF cP[1] IN HB THEN
		SELECT bInst FROM
		  qLL =>
		    IF -- RiImplemented[read][local][short][double] AND 
		    bP[1] IN LocalHB THEN 
		      {P5.C2[qRLDI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLG =>
		    IF -- RiImplemented[read][global][short][double] AND 
		    bP[1] IN GlobalHB THEN 
		      {P5.C2[qRGDI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLLK =>
		    IF cP[1] = 0 THEN {P5.C1[qRKDI, bP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  ENDCASE => canSlide ← TRUE;
	    qWD =>
	      IF cP[1] IN HB THEN
		SELECT bInst FROM
		  qLL =>
		    IF -- RiImplemented[write][local][short][double] AND 
		    bP[1] IN LocalHB THEN 
		      {P5.C2[qWLDI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLG =>
		    IF -- RiImplemented[write][global][short][double] AND 
		    bP[1] IN GlobalHB THEN 
		      {P5.C2[qWGDI, bP[1], cP[1]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  ENDCASE => canSlide ← TRUE;
	    qRF =>
	      IF cP[1] IN HB THEN
		SELECT bInst FROM
		  qLL =>
		    IF -- RiImplemented[read][local][short][field] AND 
		    bP[1] IN LocalHB THEN 
		      {P5.C3[qRLIF, bP[1], cP[1], cP[2]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLG =>
		    IF -- RiImplemented[read][global][short][field] AND 
		    bP[1] IN GlobalHB THEN 
		      {P5.C3[qRGIF, bP[1], cP[1], cP[2]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  ENDCASE => canSlide ← TRUE;
	    qWF =>
	      IF cP[1] IN HB THEN
		SELECT bInst FROM
		  qLL =>
		    IF RiImplemented[write][local][short][field] AND 
		    bP[1] IN LocalHB THEN 
		      {P5.C3[qWLIF, bP[1], cP[1], cP[2]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  qLG =>
		    IF -- RiImplemented[write][global][short][field] AND 
		    bP[1] IN GlobalHB THEN 
		      {P5.C3[qWGIF, bP[1], cP[1], cP[2]]; Delete2[b,c]}
		    ELSE canSlide ← TRUE;
		  ENDCASE => canSlide ← TRUE;
	    ENDCASE => canSlide ← TRUE;
	  END; -- of OPEN state
	ENDCASE => canSlide ← FALSE; -- of WITH
      ENDLOOP;
    END;

  
  Peep10: PUBLIC PROC =
    BEGIN -- expand families
    OPEN FOpCodes;
    ci: CCIndex;
    next: CCIndex ← start;
    state: PeepState;
    canSlide: BOOL ← FALSE;
    UNTIL (ci ← next) = CCNull DO
      next ← NextInteresting[ci];
      WITH cb[ci] SELECT FROM
	code =>
	  BEGIN OPEN state;
	  LoadLocal: PROC =
	    BEGIN
	    SELECT bInst FROM
	      qSL => IF bP[1] = cP[1] THEN {cb[b].inst ← qPL; RETURN};
	      qLL => IF bP[1] = cP[1] THEN {P5.C0[qDUP]; RETURN};
	      ENDCASE;
	    P5.C1[qLL, cP[1]];
	    END;
	  LoadGlobal: PROC =
	    BEGIN
	    SELECT bInst FROM
	      qSG => IF bP[1] = cP[1] THEN {P5.C0[qREC]; RETURN};
	      qLG => IF bP[1] = cP[1] THEN {P5.C0[qDUP]; RETURN};
	      ENDCASE;
	    P5.C1[qLG, cP[1]];
	    END;
	  LoadLocalDbl: PROC =
	    BEGIN
	    SELECT bInst FROM
	      qSLD => IF bP[1] = cP[1] THEN {cb[b].inst ← qPLD; RETURN};
	      qLLD => IF bP[1] = cP[1] THEN {P5.C0[qDDUP]; RETURN};
	      ENDCASE;
	    P5.C1[qLLD, cP[1]];
	    END;
	  LoadGlobalDbl: PROC =
	    BEGIN
	    SELECT bInst FROM
	      qSGD => IF bP[1] = cP[1] THEN {P5.C0[qREC2]; RETURN};
	      qLGD => IF bP[1] = cP[1] THEN {P5.C0[qDDUP]; RETURN};
	      ENDCASE;
	    P5.C1[qLGD, cP[1]];
	    END;
	  IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]]
	  ELSE InitParameters[@state, LOOPHOLE[ci], abc];
	  canSlide ← FALSE;
	  SELECT cInst FROM
	    -- expand out-of-range families
	    qRLI => IF ~RiImplemented[read][local][short][single] THEN {
	      LoadLocal[];
	      P5.C1[qR, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRGI => IF ~RiImplemented[read][global][short][single] THEN {
	      LoadGlobal[];
	      P5.C1[qR, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRLDI => IF ~RiImplemented[read][local][short][double] THEN {
	      LoadLocal[];
	      P5.C1[qRD, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRGDI => IF ~RiImplemented[read][global][short][double] THEN {
	      LoadGlobal[];
	      P5.C1[qRD, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRLIF => IF ~RiImplemented[read][local][short][field] THEN {
	      LoadLocal[];
	      P5.C2[qRF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    qRGIF => IF ~RiImplemented[read][global][short][field] THEN {
	      LoadGlobal[];
	      P5.C2[qRF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    qRLIL => IF ~RiImplemented[read][local][long][single] THEN {
	      LoadLocalDbl[];
	      P5.C1[qRL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRGIL => IF ~RiImplemented[read][global][long][single] THEN {
	      LoadGlobalDbl[];
	      P5.C1[qRL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRLDIL => IF ~RiImplemented[read][local][long][double] THEN {
	      LoadLocalDbl[];
	      P5.C1[qRDL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRGDIL => IF ~RiImplemented[read][global][long][double] THEN {
	      LoadGlobalDbl[];
	      P5.C1[qRDL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qRLILF => IF ~RiImplemented[read][local][long][field] THEN {
	      LoadLocalDbl[];
	      P5.C2[qRLF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    qRGILF => IF ~RiImplemented[read][global][long][field] THEN {
	      LoadGlobalDbl[];
	      P5.C2[qRLF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    qWLI => IF ~RiImplemented[write][local][short][single] THEN {
	      LoadLocal[];
	      P5.C1[qW, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWGI => IF ~RiImplemented[write][global][short][single] THEN {
	      LoadGlobal[];
	      P5.C1[qW, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWLDI => IF ~RiImplemented[write][local][short][double] THEN {
	      LoadLocal[];
	      P5.C1[qWD, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWGDI => IF ~RiImplemented[write][global][short][double] THEN {
	      LoadGlobal[];
	      P5.C1[qWD, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWLIF => IF ~RiImplemented[write][local][short][field] THEN {
	      LoadLocal[];
	      P5.C2[qWF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    qWGIF => IF ~RiImplemented[write][global][short][field] THEN {
	      LoadGlobal[];
	      P5.C2[qWF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    qWLIL => IF ~RiImplemented[write][local][long][single] THEN {
	      LoadLocalDbl[];
	      P5.C1[qWL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWGIL => IF ~RiImplemented[write][global][long][single] THEN {
	      LoadGlobalDbl[];
	      P5.C1[qWL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWLDIL => IF ~RiImplemented[write][local][long][double] THEN {
	      LoadLocalDbl[];
	      P5.C1[qWDL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWGDIL => IF ~RiImplemented[write][global][long][double] THEN {
	      LoadGlobalDbl[];
	      P5.C1[qWDL, cP[2]];
	      P5U.DeleteCell[c]}; 
	    qWLILF => IF ~RiImplemented[write][local][long][field] THEN {
	      LoadLocalDbl[];
	      P5.C2[qWLF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    qWGILF => IF ~RiImplemented[write][global][long][field] THEN {
	      LoadGlobalDbl[];
	      P5.C2[qWLF, cP[2], cP[3]];
	      P5U.DeleteCell[c]}; 
	    ENDCASE => GO TO Slide;
	  EXITS
	    Slide => canSlide ← TRUE;
	  END; -- of OPEN state
	ENDCASE => canSlide ← FALSE; -- of WITH
      ENDLOOP;
    END;

  Peep1: PUBLIC PROC =
    BEGIN -- expand families
    OPEN FOpCodes;
    ci: CCIndex;
    next: CCIndex ← start;
    state: PeepState;
    canSlide: BOOL ← FALSE;
    UNTIL (ci ← next) = CCNull DO
      next ← NextInteresting[ci];
      WITH cc: cb[ci] SELECT FROM
	code =>
	  BEGIN OPEN state;
	  IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]]
	  ELSE InitParameters[@state, LOOPHOLE[ci], abc];
	  canSlide ← FALSE;
	  SELECT cInst FROM
	    -- expand out-of-range families
	    qEFC, qLLK =>
	      IF cP[1] NOT IN BYTE THEN SIGNAL CPtr.CodeNotImplemented;
	    qLKB =>
	      IF cP[1] NOT IN BYTE THEN
		BEGIN
		cb[c].parameters[1] ← 377B;
		P5.C1[qLL, LocalBase];
		P5.LoadConstant[cP[1]-377B];
		P5.C0[qSUB]; P5.C1[qSL, LocalBase];
		END
	      ELSE canSlide ← TRUE;
	    qREC => SELECT bInst FROM 
	      qWS => {cb[b].inst ← qPS; P5U.DeleteCell[c]};
	      qWSD => {cb[b].inst ← qPSD; P5U.DeleteCell[c]};
	      qWSF => {cb[b].inst ← qPSF; P5U.DeleteCell[c]};
	      qREC => SELECT aInst FROM
	        qWSL => {cb[a].inst ← qPSL; Delete2[b, c]};
	        qWSDL => {cb[a].inst ← qPSDL; Delete2[b, c]};
	        qWSLF => {cb[a].inst ← qPSLF; Delete2[b, c]};
	        ENDCASE => GO TO Slide;
	      ENDCASE =>  GO TO Slide;
	    qREC2 => SELECT bInst FROM 
	      qWSL => {cb[b].inst ← qPSL; P5U.DeleteCell[c]};
	      qWSDL => {cb[b].inst ← qPSDL; P5U.DeleteCell[c]};
	      qWSLF => {cb[b].inst ← qPSLF; P5U.DeleteCell[c]};
	      ENDCASE =>  GO TO Slide;
	    qDBS, qDB =>
	      BEGIN
	      cc.parameters[1] ← cP[1]*2; -- N.B. this is exeuted only once
	      END;
	    qADD, qMUL, qAND, qIOR, qXOR =>
	      IF bInst = qEXCH THEN P5U.DeleteCell[b] ELSE GO TO Slide;
	    qDADD, qDMUL =>
	      IF bInst = qDEXCH THEN P5U.DeleteCell[b] ELSE GO TO Slide;
	    qW, qWF =>
	      IF bInst = qEXCH THEN 
		BEGIN
		WSOp: ARRAY [FOpCodes.qW..FOpCodes.qWF] OF BYTE = [
		  FOpCodes.qWS, FOpCodes.qNULL, FOpCodes.qNULL, FOpCodes.qWSF];
		P5U.DeleteCell[b]; cc.inst ← WSOp[cInst];
		END
	      ELSE GO TO Slide;
	    qWS, qWSF =>
	      IF bInst = qEXCH AND ~NextIsPush[c] THEN 
		BEGIN
		NonWS: ARRAY [FOpCodes.qWS..FOpCodes.qWSF] OF BYTE = [
		  FOpCodes.qW, FOpCodes.qNULL, FOpCodes.qNULL, FOpCodes.qWF];
		P5U.DeleteCell[b]; cc.inst ← NonWS[cInst];
		END
	      ELSE GO TO Slide;
	    qEXCH =>
	      IF bInst = qEXCH THEN Delete2[b,c]
	      ELSE IF LoadInst[b] AND LoadInst[a] THEN
		BEGIN
		P5U.DeleteCell[c];
		CommuteCells[a,b];
		END
	      ELSE GO TO Slide;
	    qDEXCH =>
	      IF bInst = qDEXCH THEN Delete2[b,c]
	      ELSE IF DblLoadInst[b] AND DblLoadInst[a] THEN
		BEGIN
		P5U.DeleteCell[c];
		CommuteCells[a,b];
		END
	      ELSE GO TO Slide;
	    ENDCASE => GO TO Slide;
	  EXITS
	    Slide => canSlide ← TRUE;
	  END; -- of OPEN state
	jump =>
	  BEGIN
          RJump: ARRAY JumpType[JumpE..UJumpLE] OF JumpType = [
	    JumpE, JumpN, JumpG, JumpLE, JumpL, JumpGE,
	    UJumpG, UJumpLE, UJumpL, UJumpGE];
	  canSlide ← FALSE;
	  IF cc.jtype IN [JumpE..UJumpLE] THEN
	    BEGIN
	    prev: CCIndex ← PrevInteresting[ci];
	    WITH cb[prev] SELECT FROM
	      code =>
		IF ~realinst AND inst = qEXCH AND
		 ~PushFollows[LOOPHOLE[ci,JumpCCIndex]] THEN 
		  {P5U.DeleteCell[prev]; cc.jtype ← RJump[cc.jtype]};
	      ENDCASE;
	    END;
	  END;
	ENDCASE => canSlide ← FALSE; -- of WITH
      ENDLOOP;
    END;

  PushFollows: PROC [c: JumpCCIndex] RETURNS [BOOL] =
    BEGIN -- c is conditional jump; TRUE if PUSH follows on either branch
    next: CCIndex;
    IF NextIsPush[c] THEN RETURN [TRUE];
    IF (next←NextInteresting[cb[c].destlabel]) # CCNull THEN
      WITH cb[next] SELECT FROM
        code => IF ~realinst AND inst = FOpCodes.qREC THEN RETURN [TRUE];
        ENDCASE;
    RETURN [FALSE]
    END;

  NextIsPush: PUBLIC PROC [c: CCIndex] RETURNS [BOOL] =
    BEGIN -- TRUE if PUSH follows
    FOR next: CCIndex ← NextInteresting[c], NextInteresting[next] WHILE next # CCNull DO
      WITH cb[next] SELECT FROM
        code => IF ~realinst AND inst = FOpCodes.qREC THEN RETURN [TRUE]
		ELSE EXIT;
	label => NULL;
        ENDCASE => EXIT;
      ENDLOOP;
    RETURN [FALSE]
    END;

  END.