
<<file: PeepholeA.mesa>>
<<last edited by Sweet on  7-Sep-82 11:08:01>>
<<last edited by Satterthwaite on December 1, 1985 4:27:22 pm PST>>

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.

