-- file: PeepholeQ.mesa
-- last edited by Sweet on 5-Oct-82 11:26:03
-- last edited by Satterthwaite on December 16, 1982 9:48 am
DIRECTORY
Alloc: TYPE USING [Notifier],
Code: TYPE USING [CodePassInconsistency, codeptr],
CodeDefs: TYPE USING [
Base, CCIndex, CCNull, CodeCCIndex, codeType, JumpCCIndex, JumpType],
FOpCodes: TYPE USING [
qACD, qADC, qADD, qADDSB, qAL0IB, qAMUL, qAND, qDADD, qDBL,
qDBS, qDDBL, qDDUP, qDEC, qDI, qDINC, qDIS, qDIS2, qDMUL, qDSHIFT,
qDSK, qDSUB, qDUDIV, qDUP, qEFC, qEI, qEXCH, qEXDIS, qGA, qINC,
qIOR, qKFCB, qLA, qLFC, qLG, qLGD, qLI, qLID, qLL, qLLD, qLLK, qLP,
qLSTE, qLSTF, qMUL, qNEG, qNULL, qPI, qPL, qPLD, qPO, qPS,
qPSCDL, qPSCIDL, qPSD, qPSDL, qPSF, qPSL, qPSLF, qR, qRD, qRDL,
qREC, qREC2, qRET, qRF, qRGDI, qRGDIL, qRGI, qRGIL, qRGILF,
qRKDI, qRKI, qRL, qRLDI, qRLDIL, qRLF, qRLI, qRLIF, qRLIL, qRLILF,
qRSTR, qRSTRL, qSDIV, qSFC, qSG, qSGD, qSHIFT, qSHIFTSB, qSL, qSLD,
qSUB, qTRPL, qUDIV, qWDL, qWF, qWGDI, qWGDIL, qWGI, qWGIL, qWGILF,
qWL, qWLDI, qWLDIL, qWLF, qWLI, qWLIL, qWLILF, qWS, qWSCDL,
qWSCIDL, qWSD, qWSDL, qWSF, qWSL, qWSLF, qWSTR, qWSTRL, qXOR],
Inline: TYPE USING [BITAND, BITSHIFT],
OpCodeParams: TYPE USING [BYTE, GlobalHB, HB, LocalBase, LocalHB],
P5: TYPE USING [PopEffect, PushEffect, C0, C1, C2, C3, LoadConstant],
P5U: TYPE USING [DeleteCell],
PeepholeDefs: TYPE USING [
ConsPeepState, DblLoadInst, Delete2, Delete3, InitConsState, InitJParametersBC,
InitParameters, JumpPeepState, LoadInst, NextInteresting, NextIsPush, PeepholeANotify,
PeepholeUNotify, PeepholeZNotify, Peep1, Peep2, Peep10, PeepState, PeepZ,
SetRealInst, SlideConsState, SlidePeepState2, UnpackFD],
PrincOps: TYPE USING [FieldDescriptor];
PeepholeQ: PROGRAM
IMPORTS CPtr: Code, Inline, P5, P5U, PeepholeDefs
EXPORTS CodeDefs, P5, PeepholeDefs =
BEGIN OPEN PeepholeDefs, OpCodeParams, CodeDefs;
-- imported definitions
BYTE: TYPE = OpCodeParams.BYTE;
qNULL: BYTE = FOpCodes.qNULL;
cb: CodeDefs.Base; -- code base (local copy)
DummyProc: PROC =
BEGIN -- every 2 minutes of compile time helps
s: PeepState;
js: JumpPeepState;
IF FALSE THEN [] ← s;
IF FALSE THEN [] ← js;
END;
PeepholeNotify: PUBLIC Alloc.Notifier =
BEGIN -- called by allocator whenever table area is repacked
cb ← base[codeType];
PeepholeANotify[base]; PeepholeZNotify[base]; PeepholeUNotify[base];
END;
start: PUBLIC CodeCCIndex;
PeepHole: PUBLIC PROC [s: CCIndex] =
BEGIN
start ← LOOPHOLE[s];
SetRealInst[FALSE];
Peep0[]; -- remove POPs by modifying previous instruction
Peep1[]; -- expand families
Peep2[]; -- discover short magic
Peep5[]; -- discover long magic
Peep3[]; -- discover doubles (shouldn't uncover any long magic)
Peep4[]; -- long arithmetic: INC and DEC, MUL to SHIFT etc
Peep5a[]; -- constructor stuff
Peep3[]; -- discover doubles again (5a may have uncovered some)
Peep6[]; -- sprinkle single DUPs
Peep7[]; -- sprinkle double DUPs
Peep8[]; -- PUTs and PUSHs, RF and WF to RSTR and WSTR
Peep9[]; -- long PUTs and PUSHs
Peep10[]; -- expand unimplemented magic
Peep11[]; -- short arithmetic: INC and DEC, MUL to SHIFT etc
Peep13[]; -- find special jumps
SetRealInst[TRUE];
PeepZ[start];
END;
BackupCP: PROC [n: INTEGER] RETURNS [INTEGER] =
BEGIN OPEN FOpCodes; -- back up codeptr n stack positions
cc: CCIndex ← CPtr.codeptr;
netEffect: INTEGER;
WHILE (cc ← cb[cc].blink) # CCNull AND n # 0 DO
WITH cb[cc] SELECT FROM
code =>
BEGIN
IF realinst THEN EXIT;
SELECT inst FROM
qEFC, qLFC, qSFC, qKFCB, qRET, qPO, qPI, qLSTE, qLSTF, qDSK => EXIT;
ENDCASE;
netEffect ← P5.PushEffect[inst] - P5.PopEffect[inst];
IF n < netEffect THEN EXIT;
n ← n - netEffect;
END;
other => IF otag = table THEN EXIT;
ENDCASE => EXIT;
ENDLOOP;
CPtr.codeptr ← cc;
RETURN [n]
END;
InsertPOP: PROC [n: INTEGER] =
BEGIN OPEN FOpCodes; -- insert (or simulate) a POP of the word at tos-n
saveCodePtr: CCIndex ← CPtr.codeptr;
n ← BackupCP[n];
SELECT n FROM
0 => P5.C0[qDIS];
1 => {P5.C0[qEXCH]; P5.C0[qDIS]};
2 => {P5.C0[qDIS]; P5.C0[qEXCH]; P5.C0[qREC]; P5.C0[qEXCH]; P5.C0[qDIS]};
3 =>
BEGIN
P5.C0[qDIS]; P5.C0[qDIS]; P5.C0[qEXCH]; P5.C0[qREC]; P5.C0[qEXCH];
P5.C0[qREC]; P5.C0[qEXCH]; P5.C0[qDIS];
END;
ENDCASE => SIGNAL CPtr.CodePassInconsistency;
CPtr.codeptr ← saveCodePtr;
END;
Peep0: PUBLIC PROC =
BEGIN -- remove POPs by modifying previous instruction
OPEN FOpCodes;
next, ci: CCIndex;
changed: BOOL ← TRUE;
WHILE changed DO
next ← start;
changed ← FALSE;
UNTIL (ci ← next) = CCNull DO
next ← NextInteresting[ci];
WITH cb[ci] SELECT FROM
code => IF ~realinst THEN SELECT inst FROM
qDIS => changed ← changed OR RemoveThisPop[ci];
qDIS2 => {
inst ← qDIS;
CPtr.codeptr ← ci; P5.C0[qDIS];
next ← CPtr.codeptr;
changed ← changed OR RemoveThisPop[ci]};
ENDCASE;
ENDCASE;
ENDLOOP;
ENDLOOP;
END;
RemoveThisPop: PUBLIC PROC [ci: CCIndex] RETURNS [didThisTime: BOOL] =
BEGIN -- remove POP by modifying previous instruction, if possible
OPEN FOpCodes;
state: PeepState;
didThisTime ← FALSE;
WITH cb[ci] SELECT FROM
code =>
BEGIN OPEN state;
InitParameters[@state, LOOPHOLE[ci], abc];
SELECT cInst FROM
qDIS =>
IF Popable[bInst] THEN
{P5U.DeleteCell[b]; P5U.DeleteCell[c]; didThisTime ← TRUE}
ELSE
SELECT bInst FROM
qR, qRF, qNEG, qDBS, qINC, qDEC =>
BEGIN
P5U.DeleteCell[b];
[] ← RemoveThisPop[c]; -- the blink may be popable now
-- above is unnecessary if called from Peep1
-- but useful if called from jump elimination
didThisTime ← TRUE;
END;
qRSTR, qADD, qSUB, qMUL, qAMUL, qUDIV, qSDIV, qAND, qIOR, qXOR,
qSHIFT, qRL, qRLF =>
BEGIN
np: CCIndex;
P5U.DeleteCell[b];
CPtr.codeptr ← cb[c].blink;
P5.C0[qDIS];
np ← CPtr.codeptr;
[] ← RemoveThisPop[np]; [] ← RemoveThisPop[c];
END;
-- should add arm for RLFS
qDADD =>
IF Popable[aInst] THEN
BEGIN
Delete2[a,b];
InsertPOP[1];
P5.C0[qADD];
P5U.DeleteCell[c];
didThisTime ← TRUE;
END;
qLGD => {cb[b].inst ← qLG; P5U.DeleteCell[c]; didThisTime ← TRUE};
qLLD => {cb[b].inst ← qLL; P5U.DeleteCell[c]; didThisTime ← TRUE};
qLID => {cb[b].inst ← qLI; P5U.DeleteCell[c]; didThisTime ← TRUE};
qRD => {cb[b].inst ← qR; P5U.DeleteCell[c]; didThisTime ← TRUE};
qRDL => {cb[b].inst ← qRL; P5U.DeleteCell[c]; didThisTime ← TRUE};
qRGDI => {
cb[b].inst ← qRGI; P5U.DeleteCell[c]; didThisTime ← TRUE};
qRGDIL => {
cb[b].inst ← qRGIL; P5U.DeleteCell[c]; didThisTime ← TRUE};
qRKDI => {
cb[b].inst ← qRKI; P5U.DeleteCell[c]; didThisTime ← TRUE};
qRLDI => {
cb[b].inst ← qRLI; P5U.DeleteCell[c]; didThisTime ← TRUE};
qRLDIL => {
cb[b].inst ← qRLIL; P5U.DeleteCell[c]; didThisTime ← TRUE};
qDI, qEI => {CommuteCells[b,c]; didThisTime ← TRUE};
-- could handle qACD and qADC when have more time to think thru
qEXCH =>
IF IsLoad[aInst] THEN
BEGIN
Delete2[b, c];
CPtr.codeptr ← cb[a].blink;
P5.C0[qDIS];
[] ← RemoveThisPop[CPtr.codeptr];
didThisTime ← TRUE;
END
ELSE {cb[c].inst ← qEXDIS; P5U.DeleteCell[b]; didThisTime ← TRUE};
ENDCASE;
ENDCASE;
END;
ENDCASE; -- of WITH
END;
Popable: PROC [inst: BYTE] RETURNS [BOOL] =
BEGIN
RETURN [inst#qNULL AND
(P5.PopEffect[inst]=0 AND P5.PushEffect[inst]=1 OR inst = FOpCodes.qDUP)]
END;
IsLoad: PROC [inst: BYTE] RETURNS [BOOL] =
BEGIN
RETURN [inst#qNULL AND inst # FOpCodes.qREC AND
(P5.PopEffect[inst]=0 AND P5.PushEffect[inst]=1)]
END;
Peep5: PUBLIC PROC =
BEGIN -- discover long 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
qRL =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qLLD =>
IF -- RiImplemented[read][local][long][single] AND
bP[1] IN LocalHB THEN
{P5.C2[qRLIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
qLGD =>
IF -- RiImplemented[read][global][long][single] AND
bP[1] IN GlobalHB THEN
{P5.C2[qRGIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE;
qWL =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qLLD =>
IF -- RiImplemented[write][local][long][single] AND
bP[1] IN LocalHB THEN
{P5.C2[qWLIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
qLGD =>
IF -- RiImplemented[write][global][long][single] AND
bP[1] IN GlobalHB THEN
{P5.C2[qWGIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE;
qRDL =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qLLD =>
IF -- RiImplemented[read][local][long][double] AND
bP[1] IN LocalHB THEN
{P5.C2[qRLDIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
qLGD =>
IF -- RiImplemented[read][global][long][double] AND
bP[1] IN GlobalHB THEN
{P5.C2[qRGDIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE;
qWDL =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qLLD =>
IF -- RiImplemented[write][local][long][double] AND
bP[1] IN LocalHB THEN
{P5.C2[qWLDIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
qLGD =>
IF -- RiImplemented[write][global][long][double] AND
bP[1] IN GlobalHB THEN
{P5.C2[qWGDIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE;
qRLF =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qLLD =>
IF -- RiImplemented[read][local][long][field] AND
bP[1] IN LocalHB THEN
{P5.C3[qRLILF, bP[1], cP[1], cP[2]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
qLGD =>
IF -- RiImplemented[read][global][long][field] AND
bP[1] IN GlobalHB THEN
{P5.C3[qRGILF, bP[1], cP[1], cP[2]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE;
qWLF =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qLLD =>
IF -- RiImplemented[write][local][long][field] AND
bP[1] IN LocalHB THEN
{P5.C3[qWLILF, bP[1], cP[1], cP[2]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
qLGD =>
IF -- RiImplemented[write][global][long][field] AND
bP[1] IN GlobalHB THEN
{P5.C3[qWGILF, 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;
Peep5a: PUBLIC PROC =
BEGIN -- constructor stuff
OPEN FOpCodes;
di: CCIndex;
next: CCIndex;
state: ConsPeepState;
didSomething: BOOL ← TRUE;
canSlide: BOOL ← FALSE;
WHILE didSomething DO
next ← start;
didSomething ← FALSE;
UNTIL (di ← next) = CCNull DO
next ← NextInteresting[di];
WITH dd: cb[di] SELECT FROM
code =>
BEGIN OPEN state;
IF canSlide THEN SlideConsState[@state, LOOPHOLE[di]]
ELSE InitConsState[@state, LOOPHOLE[di]];
SELECT d.inst FROM
qPSF, qWSF =>
IF c.inst = qLI AND b.inst = qPSF AND a.inst = qLI THEN
BEGIN
newOp: BYTE = IF d.inst = qPSF THEN qPS ELSE qWS;
mask: ARRAY [0..16] OF CARDINAL = [
0, 1, 3, 7, 17B, 37B, 77B, 177B, 377B,
777B, 1777B, 3777B, 7777B, 17777B, 37777B,
77777B, 177777B];
p1, s1, p2, s2, v: CARDINAL;
fd: PrincOps.FieldDescriptor;
FullWord: PrincOps.FieldDescriptor = [offset: 0, posn: 0, size: 16];
IF b.params[1] # d.params[1] THEN GO TO slide;
[p: p1, s: s1] ← UnpackFD[LOOPHOLE[b.params[2]]];
[p: p2, s: s2] ← UnpackFD[LOOPHOLE[d.params[2]]];
IF p1+s1 # p2 THEN GO TO slide;
v ← Inline.BITSHIFT[a.params[1], s2] + Inline.BITAND[c.params[1], mask[s2]];
fd ← [offset: 0, posn: p1, size: s1+s2];
IF fd = FullWord THEN {
P5.C1[newOp, d.params[1]];
Delete3[a.index, b.index, d.index]}
ELSE {
cb[d.index].parameters[2] ← LOOPHOLE[fd];
Delete2[a.index, b.index]};
cb[c.index].parameters[1] ← v;
didSomething ← TRUE;
canSlide ← FALSE;
END;
qPSLF, qWSLF =>
IF c.inst = qLI AND b.inst = qPSLF AND a.inst = qLI THEN
BEGIN
newOp: BYTE = IF d.inst = qPSLF THEN qPSL ELSE qWSL;
mask: ARRAY [0..16] OF CARDINAL = [
0, 1, 3, 7, 17B, 37B, 77B, 177B, 377B,
777B, 1777B, 3777B, 7777B, 17777B, 37777B,
77777B, 177777B];
p1, s1, p2, s2, v: CARDINAL;
fd: PrincOps.FieldDescriptor;
FullWord: PrincOps.FieldDescriptor = [offset: 0, posn: 0, size: 16];
IF b.params[1] # d.params[1] THEN GO TO slide;
[p: p1, s: s1] ← UnpackFD[LOOPHOLE[b.params[2]]];
[p: p2, s: s2] ← UnpackFD[LOOPHOLE[d.params[2]]];
IF p1+s1 # p2 THEN GO TO slide;
v ← Inline.BITSHIFT[a.params[1], s2] + Inline.BITAND[c.params[1], mask[s2]];
fd ← [offset: 0, posn: p1, size: s1+s2];
IF fd = FullWord THEN {
P5.C1[newOp, d.params[1]];
Delete3[a.index, b.index, d.index]}
ELSE {
cb[d.index].parameters[2] ← LOOPHOLE[fd];
Delete2[a.index, b.index]};
cb[c.index].parameters[1] ← v;
didSomething ← TRUE;
canSlide ← FALSE;
END;
qPS, qWS =>
BEGIN
newOp: BYTE = IF d.inst = qPS THEN qPSD ELSE qWSD;
IF LoadInst[c.index] AND b.inst = qPS AND LoadInst[a.index]
AND b.params[1] + 1 = d.params[1] THEN
BEGIN
cb[d.index].inst ← newOp;
cb[d.index].parameters[1] ← b.params[1];
P5U.DeleteCell[b.index];
didSomething ← TRUE;
canSlide ← FALSE;
END
ELSE canSlide ← TRUE;
END;
qPSL, qWSL =>
BEGIN
newOp: BYTE = IF d.inst = qPSL THEN qPSDL ELSE qWSDL;
IF LoadInst[c.index] AND b.inst = qPSL AND LoadInst[a.index]
AND b.params[1] + 1 = d.params[1] THEN
BEGIN
cb[d.index].inst ← newOp;
cb[d.index].parameters[1] ← b.params[1];
P5U.DeleteCell[b.index];
didSomething ← TRUE;
canSlide ← FALSE;
END
ELSE canSlide ← TRUE;
END;
qSL, qSG =>
BEGIN
newOp: BYTE = IF d.inst = qSL THEN qSLD ELSE qSGD;
IF LoadInst[c.index] AND b.inst = d.inst AND LoadInst[a.index]
AND b.params[1] + 1 = d.params[1] AND ~NextIsPush[d.index] THEN
BEGIN
cb[d.index].inst ← newOp;
cb[d.index].parameters[1] ← b.params[1];
P5U.DeleteCell[b.index];
didSomething ← TRUE;
canSlide ← FALSE;
END
ELSE canSlide ← TRUE;
END;
ENDCASE => canSlide ← TRUE;
EXITS
slide => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
ENDLOOP; -- of WHILE didSomething
END;
Peep6: PUBLIC PROC =
BEGIN -- sprinkle single DUPs
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
-- replace load,load with load,DUP
qLI =>
IF bInst = cInst AND cP[1] = bP[1] THEN
IF cP[1] = 0 THEN {P5.C1[qLID, 0]; Delete2[b, c]}
ELSE {P5.C0[qDUP]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qLP =>
IF bInst = qLI AND bP[1] = 0 THEN {
P5.C1[qLID, 0]; Delete2[b, c]}
ELSE canSlide ← TRUE;
qLL, qLG, qLLK, qLA, qGA =>
IF bInst = cInst AND cP[1] = bP[1] THEN {
P5.C0[qDUP]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qRLI, qRGI, qRLIL, qRGIL, qRKI =>
IF bInst = cInst AND cP[1] = bP[1] AND
cP[2] = bP[2] THEN
{P5.C0[qDUP]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qRLIF, qRLILF =>
IF bInst = cInst AND cP[1] = bP[1] AND
cP[2] = bP[2] AND cP[3] = bP[3] THEN
{P5.C0[qDUP]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Peep7: PUBLIC PROC =
BEGIN -- sprinkle double DUPs
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
-- replace load,load with load,DDUP
qLLD, qLGD =>
IF bInst = cInst AND cP[1] = bP[1] THEN {P5.C0[qDDUP]; P5U.DeleteCell[c]};
qRLDI, qRLDIL, qRKDI =>
IF bInst = cInst AND cP[1] = bP[1] AND cP[2] = bP[2] THEN
{P5.C0[qDDUP]; P5U.DeleteCell[c]};
ENDCASE => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Peep8: PUBLIC PROC =
BEGIN -- PUTs and PUSHs, RF and WF to RSTR and WSTR
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
qLL =>
IF bInst = qSL AND cP[1] IN BYTE AND cP[1] = bP[1] THEN
{cb[b].inst ← qPL; P5U.DeleteCell[c]}
ELSE IF bInst = qSLD AND cP[1] = bP[1] THEN
{CPtr.codeptr ← b; P5.C0[qREC]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qREC => SELECT bInst FROM
qSL => IF bP[1] IN BYTE THEN {cb[b].inst ← qPL; P5U.DeleteCell[c]};
qREC => {cb[b].inst ← qREC2; P5U.DeleteCell[c]};
ENDCASE => GO TO Slide;
qLG =>
IF (bInst = qSG OR bInst = qSGD) AND cP[1] = bP[1] THEN
{CPtr.codeptr ← b; P5.C0[qREC]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRLI =>
IF (bInst = qWLI OR bInst = qWLDI) AND
cP[1] = bP[1] AND cP[2] = bP[2] THEN
{CPtr.codeptr ← b; P5.C0[qREC]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRLIL =>
IF (bInst = qWLIL OR bInst = qWLDIL)
AND cP[1] = bP[1] AND cP[2] = bP[2] THEN
{CPtr.codeptr ← b; P5.C0[qREC]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRF, qWF, qRLF, qWLF =>
BEGIN
position, size: [0..16);
[position, size] ← UnpackFD[LOOPHOLE[cP[2]]];
IF size = 8 AND cP[1] <= BYTE.LAST/2 THEN
SELECT position FROM
0, 8 =>
BEGIN
P5.LoadConstant[0];
P5.C1[(SELECT cInst FROM
qRF => qRSTR,
qWF => qWSTR,
qRLF => qRSTRL,
ENDCASE => qWSTRL), cP[1]*2+position/8];
P5U.DeleteCell[c];
END;
ENDCASE => GO TO Slide
ELSE GO TO Slide;
END;
ENDCASE => GO TO Slide;
EXITS
Slide => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Peep9: PUBLIC PROC =
BEGIN -- long PUTs and PUSHs
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
qLL =>
IF bInst = qPL AND cP[1] = bP[1]+1 AND aInst = qSL AND aP[1] = cP[1] THEN
{cb[b].inst ← qPLD; Delete2[a, c]}
ELSE GO TO Slide;
qLLD =>
IF bInst = qSLD AND cP[1] IN BYTE AND cP[1] = bP[1] THEN
{cb[b].inst ← qPLD; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qREC2 => SELECT bInst FROM
qSLD => IF bP[1] IN BYTE THEN {cb[b].inst ← qPLD; P5U.DeleteCell[c]};
qWSL => {cb[b].inst ← qPSL; P5U.DeleteCell[c]};
qWSDL => {cb[b].inst ← qPSDL; P5U.DeleteCell[c]};
qWSLF => {cb[b].inst ← qPSLF; P5U.DeleteCell[c]};
qWSCIDL => {cb[b].inst ← qPSCIDL; P5U.DeleteCell[c]};
qWSCDL => {cb[b].inst ← qPSCDL; P5U.DeleteCell[c]};
ENDCASE => GO TO Slide;
qLGD =>
IF bInst = qSGD AND cP[1] = bP[1] THEN
{CPtr.codeptr ← b; P5.C0[qREC2]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRLDI =>
IF bInst = qWLDI AND cP[1] = bP[1] AND cP[2] = bP[2] THEN
{CPtr.codeptr ← b; P5.C0[qREC2]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRLDIL =>
IF bInst = qWLDIL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN
{CPtr.codeptr ← b; P5.C0[qREC2]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
ENDCASE => GO TO Slide;
EXITS
Slide => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Peep3: PUBLIC PROC =
BEGIN -- discover doubles
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
qLL =>
IF bInst = qLL AND cP[1] = bP[1]+1 THEN
{cb[b].inst ← qLLD; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qSL =>
IF bInst = qSL AND cP[1] = bP[1]-1 THEN
{cb[c].inst ← qSLD; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qLG =>
IF bInst = qLG AND cP[1] = bP[1]+1 THEN
{cb[b].inst ← qLGD; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qSG =>
IF bInst = qSG AND cP[1] = bP[1]-1 THEN
{cb[c].inst ← qSGD; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qRLI =>
IF bInst = qRLI AND cP[1] = bP[1] AND cP[2] = bP[2]+1 THEN
{cb[b].inst ← qRLDI; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRGI =>
IF bInst = qRGI AND cP[1] = bP[1] AND cP[2] = bP[2]+1 THEN
{cb[b].inst ← qRGDI; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRLIL =>
IF bInst = qRLIL AND cP[1] = bP[1] AND cP[2] = bP[2]+1 THEN
{cb[b].inst ← qRLDIL; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qRGIL =>
IF bInst = qRGIL AND cP[1] = bP[1] AND cP[2] = bP[2]+1 THEN
{cb[b].inst ← qRGDIL; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qWLI =>
IF bInst = qWLI AND cP[1] = bP[1] AND cP[2]+1 = bP[2] THEN
{cb[c].inst ← qWLDI; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qWGI =>
IF bInst = qWGI AND cP[1] = bP[1] AND cP[2]+1 = bP[2] THEN
{cb[c].inst ← qWGDI; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qWLIL =>
IF bInst = qWLIL AND cP[1] = bP[1] AND cP[2]+1 = bP[2] THEN
{cb[c].inst ← qWLDIL; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qWGIL =>
IF bInst = qWGIL AND cP[1] = bP[1] AND cP[2]+1 = bP[2] THEN
{cb[c].inst ← qWGDIL; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qRKI =>
IF bInst = qRKI AND cP[1] = bP[1] AND cP[2] = bP[2]+1 THEN
{cb[b].inst ← qRKDI; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qDIS =>
IF bInst = qDIS THEN
{cb[b].inst ← qDIS2; P5U.DeleteCell[c]}
ELSE GO TO Slide;
ENDCASE => GO TO Slide;
EXITS
Slide => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
CommuteCells: PUBLIC PROC [a, b: CCIndex] =
BEGIN -- could be a "source other CCItem" between,
-- in any case, move a to after b
-- see 3/5/80 notes for rationale
aPrev: CCIndex = cb[a].blink; -- never Null
aNext: CCIndex = cb[a].flink; -- probably b
bPrev: CCIndex = cb[b].blink; -- probably a
bNext: CCIndex = cb[b].flink;
cb[aPrev].flink ← aNext;
cb[aNext].blink ← aPrev;
cb[b].flink ← a;
cb[a].blink ← b; cb[a].flink ← bNext;
IF bNext # CCNull THEN cb[bNext].blink ← a;
END;
Peep11: PUBLIC PROC =
BEGIN -- short arithmetic: INC and DEC, MUL to SHIFT etc
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
canSlide: BOOL ← FALSE;
state: PeepState;
negate: BOOL ← FALSE;
D2: PROC = {Delete2[state.b, state.c]; IF negate THEN P5.C0[qNEG]};
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
qADD =>
IF bInst = qLI THEN
BEGIN
SELECT aInst FROM
qLL => IF aP[1] = LocalBase AND bP[1] IN BYTE THEN {
P5.C1[qAL0IB, bP[1]]; Delete3[a, b, c]; GO TO done};
qGA, qLA, qLI => {
cb[a].parameters[1] ← cb[a].parameters[1] + bP[1];
Delete2[b, c];
GO TO done};
qADD => {
z: CCIndex = cb[a].blink;
WITH zz: cb[z] SELECT FROM
code => IF ~zz.realinst AND zz.inst = qLI THEN {
cb[b].parameters[1] ← bP[1] ← bP[1] + zz.parameters[1];
Delete2[z, a]};
ENDCASE};
qADDSB => {
cb[b].parameters[1] ← bP[1] ← bP[1] + aP[1];
P5U.DeleteCell[a]};
qINC => {
cb[b].parameters[1] ← bP[1] ← bP[1] + 1;
P5U.DeleteCell[a]};
qDEC => {
cb[b].parameters[1] ← bP[1] ← bP[1] - 1;
P5U.DeleteCell[a]};
ENDCASE;
SELECT LOOPHOLE[bP[1], INTEGER] FROM
0 => Delete2[b,c];
1 => {cb[c].inst ← qINC; P5U.DeleteCell[b]};
-1 => {cb[c].inst ← qDEC; P5U.DeleteCell[b]};
IN [-200B..200B) => {P5.C1[qADDSB, bP[1]]; Delete2[b, c]};
ENDCASE => GO TO Slide;
EXITS
done => NULL;
END
ELSE IF bInst = qNEG THEN
{cb[c].inst ← qSUB; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qSUB =>
IF bInst = qLI THEN
BEGIN
SELECT LOOPHOLE[bP[1], INTEGER] FROM
0 => Delete2[b,c];
1 => {cb[c].inst ← qDEC; P5U.DeleteCell[b]};
-1 => {cb[c].inst ← qINC; P5U.DeleteCell[b]};
IN (-200B..200B] => {P5.C1[qADDSB, -INTEGER[bP[1]]]; Delete2[b, c]};
ENDCASE => GO TO Slide;
END
ELSE IF bInst = qNEG THEN
{cb[c].inst ← qADD; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qSHIFT =>
IF bInst = qLI THEN
SELECT INTEGER[bP[1]] FROM
1 =>
IF aInst = qSHIFTSB AND aP[1] > 0 THEN {
cb[a].parameters[1] ← aP[1] + bP[1];
Delete2[b,c]}
ELSE {cb[c].inst ← qDBL; P5U.DeleteCell[b]};
0 => Delete2[b,c];
IN [-200B..200B) =>
IF aInst = qSHIFTSB
AND INTEGER[aP[1]]*INTEGER[bP[1]] > 0 THEN {
cb[a].parameters[1] ← aP[1] + bP[1];
Delete2[b,c]}
ELSE {
P5.C1[qSHIFTSB, bP[1]];
Delete2[b, c]};
ENDCASE => GO TO Slide
ELSE GO TO Slide;
qSHIFTSB =>
IF bInst = qSHIFTSB AND INTEGER[bP[1]]*INTEGER[cP[1]] > 0 THEN {
cb[c].parameters[1] ← bP[1] + cP[1];
P5U.DeleteCell[b]}
ELSE GO TO Slide;
qMUL =>
IF bInst = qLI THEN
BEGIN
negate ← FALSE;
IF LOOPHOLE[bP[1], INTEGER] < 0 THEN
{negate ← TRUE; bP[1] ← -LOOPHOLE[bP[1], INTEGER]};
SELECT bP[1] FROM
1 => D2[];
2 => {P5.C0[qDBL]; D2[]};
3 => {P5.C0[qTRPL]; D2[]};
4 => {P5.C0[qDBL]; P5.C0[qDBL]; D2[]};
5 => {P5.C0[qDUP]; P5.C0[qDBL]; P5.C0[qDBL]; P5.C0[qADD]; D2[]};
6 => {P5.C0[qDBL]; P5.C0[qTRPL]; D2[]};
7 => {P5.C0[qDUP]; P5.C0[qDBL]; P5.C0[qTRPL]; P5.C0[qADD]; D2[]};
9 => {P5.C0[qTRPL]; P5.C0[qTRPL]; D2[]};
10 => {P5.C0[qDUP]; P5.C0[qTRPL]; P5.C0[qTRPL]; P5.C0[qADD]; D2[]};
ENDCASE =>
BEGIN
powerOf2: BOOL;
log: CARDINAL;
[powerOf2, log] ← Log2[LOOPHOLE[bP[1]]];
IF powerOf2 THEN {P5.C1[qSHIFTSB, log]; D2[]}
ELSE GO TO Slide;
END;
END;
qUDIV =>
IF bInst = qLI THEN
BEGIN
powerOf2: BOOL;
log: CARDINAL;
negate ← FALSE;
[powerOf2, log] ← Log2[LOOPHOLE[bP[1]]];
IF powerOf2 THEN {P5.C1[qSHIFTSB, -log]; D2[]}
ELSE GO TO Slide;
END;
qDIS =>
IF bInst = qEXCH THEN {cb[c].inst ← qEXDIS; P5U.DeleteCell[b]}
ELSE GO TO Slide;
ENDCASE => GO TO Slide;
EXITS
Slide => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Peep4: PUBLIC PROC =
BEGIN -- long arithmetic: INC and DEC, MUL to SHIFT etc
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
canSlide: BOOL ← FALSE;
state: PeepState;
D3: PROC = {Delete3[state.a, state.b, state.c]};
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
qDADD =>
IF bInst = qLI AND bP[1] = 0 THEN
BEGIN
IF aInst = qLI THEN SELECT aP[1] FROM
0 => {Delete3[a,b,c]; GO TO done};
1 => {cb[c].inst ← qDINC; Delete2[a,b]; GO TO done};
ENDCASE;
cb[c].inst ← qADC; P5U.DeleteCell[b];
EXITS
done => NULL;
END
ELSE IF DblLoadInst[b] AND aInst = qLI AND aP[1] = 0 THEN {
cb[c].inst ← qACD; P5U.DeleteCell[a]}
ELSE IF bInst = qLID AND bP[1] = 0 THEN Delete3[a,b,c]
ELSE GO TO Slide;
qDSUB =>
IF bInst = qLI AND bP[1] = 0 AND aInst = qLI AND aP[1] = 0 THEN
Delete3[a,b,c]
ELSE IF bInst = qLID AND bP[1] = 0 THEN Delete3[a,b,c]
ELSE GO TO Slide;
qADC =>
IF bInst = qLI THEN SELECT bP[1] FROM
1 => {cb[c].inst ← qDINC; P5U.DeleteCell[b]};
0 => Delete3[a,b,c];
ENDCASE => GO TO Slide
ELSE GO TO Slide;
qREC =>
IF bInst = qAMUL AND aInst = qLI THEN
BEGIN
SELECT aP[1] FROM
1 => D3[];
2 => {P5.C1[qLI, 0]; P5.C0[qDDBL]; D3[]};
3 => {P5.C1[qLI, 0]; P5.C0[qDDUP]; P5.C0[qDDBL]; P5.C0[qDADD]; D3[]};
4 => {P5.C1[qLI, 0]; P5.C0[qDDBL]; P5.C0[qDDBL]; D3[]};
8 => {P5.C1[qLI, 0]; P5.C0[qDDBL]; P5.C0[qDDBL]; P5.C0[qDDBL]; D3[]};
ENDCASE => GO TO Slide;
END;
qDUDIV =>
IF bInst = qLI AND bP[1] = 0 AND aInst = qLI THEN
BEGIN
powerOf2: BOOL;
log: CARDINAL;
[powerOf2, log] ← Log2[LOOPHOLE[aP[1]]];
IF powerOf2 THEN {
P5.C1[qLI, -log];
P5.C0[qDSHIFT]; D3[]}
ELSE GO TO Slide;
END;
qDMUL =>
IF bInst = qLI AND bP[1] = 0 AND aInst = qLI THEN
BEGIN
SELECT aP[1] FROM
1 => D3[];
2 => {P5.C0[qDDBL]; D3[]};
3 => {P5.C0[qDDUP]; P5.C0[qDDBL]; P5.C0[qDADD]; D3[]};
4 => {P5.C0[qDDBL]; P5.C0[qDDBL]; D3[]};
5 => {P5.C0[qDDUP]; P5.C0[qDDBL]; P5.C0[qDDBL]; P5.C0[qDADD]; D3[]};
6 => {P5.C0[qDDBL]; P5.C0[qDDUP]; P5.C0[qDDBL]; P5.C0[qDADD]; D3[]};
8 => {P5.C0[qDDBL]; P5.C0[qDDBL]; P5.C0[qDDBL]; D3[]};
ENDCASE =>
BEGIN
powerOf2: BOOL;
log: CARDINAL;
[powerOf2, log] ← Log2[LOOPHOLE[aP[1]]];
IF powerOf2 THEN {
P5.C1[qLI, log];
P5.C0[qDSHIFT]; D3[]}
ELSE GO TO Slide;
END;
END;
ENDCASE => GO TO Slide;
EXITS
Slide => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Log2: PROC [i: INTEGER] RETURNS [BOOL, CARDINAL] =
BEGIN OPEN Inline;
IF i = 0 THEN RETURN [FALSE, 0];
i ← ABS[i];
IF BITAND[i, i-1] # 0 THEN RETURN [FALSE, 0];
FOR shift: CARDINAL IN [0..16) DO
IF BITAND[i,1] = 1 THEN RETURN [TRUE, shift];
i ← BITSHIFT[i, -1];
ENDLOOP;
ERROR; -- can't be reached
END;
Peep13: PUBLIC PROC =
BEGIN -- find special jumps
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
jstate: JumpPeepState;
UNTIL (ci ← next) = CCNull DO
next ← NextInteresting[ci];
WITH jj: cb[ci] SELECT FROM
jump =>
BEGIN OPEN jstate;
InitJParametersBC[@jstate, LOOPHOLE[ci]];
SELECT jj.jtype FROM
JumpE => IF bInst = qLI THEN SELECT bP[1] FROM
0 => {jj.jtype ← ZJumpE; P5U.DeleteCell[b]};
IN [0..256) => {
jj.jtype ← BYTEJumpE; jj.jparam ← bP[1]; P5U.DeleteCell[b]};
ENDCASE;
JumpN => IF bInst = qLI THEN SELECT bP[1] FROM
0 => {jj.jtype ← ZJumpN; P5U.DeleteCell[b]};
IN [0..256) => {
jj.jtype ← BYTEJumpN; jj.jparam ← bP[1]; P5U.DeleteCell[b]};
ENDCASE;
UJumpGE => IF bInst = qLI AND bP[1] = 0 THEN
{jj.jtype ← ZJumpN; P5U.DeleteCell[b]};
ENDCASE;
END; -- of OPEN jstate
ENDCASE; -- of WITH
ENDLOOP;
END;
END.