PeepholeQ.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Sweet on August 22, 1980 4:12 PM
Satterthwaite on November 2, 1982 3:57 pm
Maxwell, August 11, 1983 9:15 am
Russ Atkinson (RRA) March 6, 1985 11:22:48 pm PST
DIRECTORY
Alloc USING [Notifier],
Code USING [CodeNotImplemented, CodePassInconsistency, codeptr],
P5U USING [DeleteCell],
CodeDefs USING [Base, CCIndex, CCNull, CodeCCIndex, codeType, JumpCCIndex, JumpType],
FOpCodes USING [qADD, qAMUL, qAND, qDADD, qDBL, qDEC, qDESCB, qDESCBS, qDIV, qDST, qDUP, qDWDC, qEFC, qEXCH, qFDESCBS, qGADRB, qINC, qIWDC, qKFCB, qLADRB, qLFC, qLG, qLGD, qLI, qLINKB, qLINT, qLL, qLLD, qLLK, qLST, qLSTF, qMUL, qNEG, qNOOP, qOR, qPL, qPOP, qPORTI, qPORTO, qPS, qPSD, qPSF, qPUSH, qR, qRD, qRET, qRF, qRFL, qRFS, qRIG, qRIGL, qRIL, qRILF, qRILL, qRL, qRSTR, qRSTRL, qRXG, qRXGL, qRXL, qRXLL, qSDIV, qSFC, qSG, qSGD, qSHIFT, qSL, qSLD, qSUB, qW, qWD, qWF, qWFL, qWIG, qWIGL, qWIL, qWILL, qWL, qWS, qWSD, qWSF, qWSTR, qWSTRL, qWXG, qWXGL, qWXL, qWXLL, qXOR],
OpCodeParams USING [BYTE, GlobalHB, HB, LocalBase, LocalHB, LocalPutSlots],
P5 USING [PopEffect, PushEffect, C0, C1, C2, LoadConstant],
PeepholeDefs USING [Delete2, Delete3, HalfByteGlobal, HalfByteLocal, InitJParametersBC, InitParameters, JumpPeepState, LoadInst, NextInteresting, PeepholeUNotify, PeepholeZNotify, PeepState, PeepZ, PrevInteresting, SetRealInst, SlidePeepState1, SlidePeepState2, UnpackFD],
PrincOps USING [sSignedDiv],
PrincOpsUtils USING [BITAND, BITSHIFT];
PeepholeQ: PROGRAM
IMPORTS CPtr: Code, P5U, P5, PeepholeDefs, PrincOpsUtils
EXPORTS CodeDefs, P5, PeepholeDefs =
BEGIN OPEN PeepholeDefs, OpCodeParams, CodeDefs;
imported definitions
BYTE: TYPE = OpCodeParams.BYTE;
qNOOP: BYTE = FOpCodes.qNOOP;
cb: CodeDefs.Base;  -- code base (local copy)
RJump: ARRAY JumpType[JumpE..UJumpLE] OF JumpType = [
JumpE, JumpN, JumpG, JumpLE, JumpL, JumpGE,
UJumpG, UJumpLE, UJumpL, UJumpGE];
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];
PeepholeZNotify[base]; PeepholeUNotify[base];
END;
start: CodeCCIndex;
PeepHole: PUBLIC PROC [s: CCIndex] =
BEGIN
start ← LOOPHOLE[s];
SetRealInst[FALSE];
Peep0[];
Peep1[];
Peep2[];
Peep3[];
Peep4[];
Peep5[];
Peep6[];
Peep7[];
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, qPORTO, qPORTI, qLST, qLSTF, qDST => 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[qPOP];
1 => {P5.C0[qEXCH]; P5.C0[qPOP]};
2 => {P5.C0[qPOP]; P5.C0[qEXCH]; P5.C0[qPUSH]; P5.C0[qEXCH]; P5.C0[qPOP]};
3 =>
BEGIN
P5.C0[qPOP]; P5.C0[qPOP]; P5.C0[qEXCH]; P5.C0[qPUSH]; P5.C0[qEXCH];
P5.C0[qPUSH]; P5.C0[qEXCH]; P5.C0[qPOP];
END;
ENDCASE => SIGNAL CPtr.CodePassInconsistency;
CPtr.codeptr ← saveCodePtr;
END;
Peep0: PROC =
BEGIN -- undo doubles
OPEN FOpCodes;
ci: CCIndex;
state: PeepState;
next: CCIndex ← start;
UNTIL (ci ← next) = CCNull DO
next ← NextInteresting[ci];
WITH cb[ci] SELECT FROM
code =>
BEGIN OPEN state;
InitParameters[@state, LOOPHOLE[ci], c];
SELECT cInst FROM
qLGD => {inst ← qLG; P5.C1[qLG, cP[1]+1]};
qLLD => {inst ← qLL; P5.C1[qLL, cP[1]+1]};
ENDCASE;
END; -- of OPEN state
ENDCASE; -- of WITH
ENDLOOP;
END;
Peep1: PROC =
BEGIN -- remove POPs by modifying previous instruction
OPEN FOpCodes;
next, ci: CCIndex;
changed: BOOLTRUE;
WHILE changed DO
next ← start;
changed ← FALSE;
UNTIL (ci ← next) = CCNull DO
next ← NextInteresting[ci];
WITH cb[ci] SELECT FROM
code =>
IF inst = qPOP AND ~realinst THEN
changed ← changed OR RemoveThisPop[ci];
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
qPOP =>
IF Popable[bInst] THEN
{P5U.DeleteCell[b]; P5U.DeleteCell[c]; didThisTime ← TRUE}
ELSE
SELECT bInst FROM
qR, qRF, qRXL, qNEG, qDESCBS, 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, qDIV, qSDIV, qAND, qOR, qXOR,
qSHIFT, qRFS, qRL, qRFL =>
BEGIN
np: CCIndex;
P5U.DeleteCell[b];
CPtr.codeptr ← cb[c].blink;
P5.C0[qPOP];
np ← CPtr.codeptr;
[] ← RemoveThisPop[np]; [] ← RemoveThisPop[c];
END;
qDADD =>
IF Popable[aInst] THEN
BEGIN
Delete2[a,b];
InsertPOP[1];
P5.C0[qADD];
P5U.DeleteCell[c];
didThisTime ← TRUE;
END;
qRD => {cb[b].inst ← qR; P5U.DeleteCell[c]; didThisTime ← TRUE};
qIWDC, qDWDC => {CommuteCells[b,c]; didThisTime ← TRUE};
qEXCH => IF IsLoad[aInst] THEN
BEGIN
Delete2[b, c];
CPtr.codeptr ← cb[a].blink;
P5.C0[qPOP];
[] ← RemoveThisPop[CPtr.codeptr];
didThisTime ← TRUE;
END;
ENDCASE;
ENDCASE;
END;
ENDCASE; -- of WITH
END;
Popable: PROC [inst: BYTE] RETURNS [BOOL] =
BEGIN
RETURN [inst#qNOOP AND
(P5.PopEffect[inst]=0 AND P5.PushEffect[inst]=1 OR inst = FOpCodes.qDUP)]
END;
IsLoad: PROC [inst: BYTE] RETURNS [BOOL] =
BEGIN
RETURN [inst#qNOOP AND inst # FOpCodes.qPUSH AND
(P5.PopEffect[inst]=0 AND P5.PushEffect[inst]=1)]
END;
Peep2: PROC =
BEGIN -- expand families
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
state: PeepState;
canSlide: BOOLFALSE;
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
expand out-of-range families
qEFC, qLLK =>
BEGIN
IF cP[1] NOT IN BYTE THEN SIGNAL CPtr.CodeNotImplemented;
canSlide ← TRUE;
END;
qLINKB =>
IF cP[1] IN BYTE THEN canSlide ← TRUE
ELSE
BEGIN
cb[c].parameters[1] ← 377B;
P5.C1[qLL, LocalBase];
P5.LoadConstant[cP[1]-377B];
P5.C0[qSUB]; P5.C1[qSL, LocalBase];
END;
qDESCBS, qDESCB, qFDESCBS =>
BEGIN
parameters[1] ← cP[1]*2;
IF cInst = qFDESCBS THEN {inst ← qDESCBS; P5.C0[qSFC]};
END;
qSDIV => {P5.C1[qKFCB, PrincOps.sSignedDiv]; P5U.DeleteCell[c]};
qDEC => {P5.LoadConstant[1]; P5.C0[qSUB]; P5U.DeleteCell[c]};
qLINT =>
BEGIN
P5.C0[qDUP];
P5.LoadConstant[0-15];
P5.C0[qSHIFT];
P5.C0[qNEG];
P5U.DeleteCell[c];
END;
qGADRB, qLADRB =>
IF cP[1] IN BYTE THEN canSlide ← TRUE
ELSE
BEGIN
parameters[1] ← BYTE.LAST;
P5.LoadConstant[cP[1]-BYTE.LAST]; P5.C0[qADD];
END;
qWS, qPS, qWSF, qPSF, qWSD, qPSD =>
BEGIN
IF cP[1] NOT IN BYTE THEN SIGNAL CPtr.CodePassInconsistency;
canSlide ← TRUE;
END;
discover family members from sequences
qR =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qADD =>
IF HalfByteLocal[a] THEN {P5.C2[qRXL, aP[1], cP[1]]; Delete3[a,b,c]}
ELSE canSlide ← TRUE;
qLL =>
IF bP[1] IN LocalHB THEN {P5.C2[qRIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
qLG =>
IF bP[1] IN GlobalHB THEN {P5.C2[qRIG, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE
ELSE canSlide ← TRUE;
qW =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qADD =>
IF HalfByteLocal[a] THEN {P5.C2[qWXL, aP[1], cP[1]]; Delete3[a,b,c]}
ELSE canSlide ← TRUE;
qLL =>
IF bP[1] IN LocalHB THEN {P5.C2[qWIL, bP[1], cP[1]]; Delete2[b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE
ELSE canSlide ← TRUE;
qRL =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qADD =>
IF aInst = qLI AND aP[1] = 0 THEN
BEGIN
aa: CCIndex = PrevInteresting[a];
IF aa # CCNull THEN WITH cc: cb[aa] SELECT FROM
code => IF HalfByteLocal[LOOPHOLE[aa]] THEN
BEGIN
P5.C2[qRXLL, cc.parameters[1], cP[1]];
Delete3[a,b,c]; P5U.DeleteCell[aa];
END
ELSE IF HalfByteGlobal[LOOPHOLE[aa]] THEN
BEGIN
P5.C2[qRXGL, cc.parameters[1], cP[1]];
Delete3[a,b,c]; P5U.DeleteCell[aa];
END
ELSE canSlide ← TRUE;
ENDCASE
ELSE canSlide ← TRUE;
END
ELSE canSlide ← TRUE;
qLL =>
IF aInst = qLL AND aP[1] IN LocalHB AND bP[1] = aP[1]+1 THEN
{P5.C2[qRILL, aP[1], cP[1]]; Delete3[a,b,c]}
ELSE canSlide ← TRUE;
qLG =>
IF aInst = qLL AND aP[1] IN GlobalHB AND bP[1] = aP[1]+1 THEN
{P5.C2[qRIGL, aP[1], cP[1]]; Delete3[a,b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE
ELSE canSlide ← TRUE;
qWL =>
IF cP[1] IN HB THEN
SELECT bInst FROM
qADD =>
IF aInst = qLI AND aP[1] = 0 THEN
BEGIN
aa: CCIndex = PrevInteresting[a];
IF aa # CCNull THEN WITH cc: cb[aa] SELECT FROM
code => IF HalfByteLocal[LOOPHOLE[aa]] THEN
BEGIN
P5.C2[qWXLL, cc.parameters[1], cP[1]];
Delete3[a,b,c]; P5U.DeleteCell[aa];
END
ELSE IF HalfByteGlobal[LOOPHOLE[aa]] THEN
BEGIN
P5.C2[qWXGL, cc.parameters[1], cP[1]];
Delete3[a,b,c]; P5U.DeleteCell[aa];
END
ELSE canSlide ← TRUE;
ENDCASE
ELSE canSlide ← TRUE;
END
ELSE canSlide ← TRUE;
qLL =>
IF aInst = qLL AND aP[1] IN LocalHB AND bP[1] = aP[1]+1 THEN
{P5.C2[qWILL, aP[1], cP[1]]; Delete3[a,b,c]}
ELSE canSlide ← TRUE;
qLG =>
IF aInst = qLL AND aP[1] IN GlobalHB AND bP[1] = aP[1]+1 THEN
{P5.C2[qWIGL, aP[1], cP[1]]; Delete3[a,b,c]}
ELSE canSlide ← TRUE;
ENDCASE => canSlide ← TRUE
ELSE canSlide ← TRUE;
qRXG =>
IF TRUE THEN
BEGIN
P5.C1[qLG, cP[1]]; P5.C0[qADD]; P5.C1[qR, cP[2]];
P5U.DeleteCell[c];
END;
qWXG =>
IF TRUE THEN
BEGIN
P5.C1[qLG, cP[1]]; P5.C0[qADD]; P5.C1[qW, cP[2]];
P5U.DeleteCell[c];
END;
qWIG =>
IF TRUE THEN
{P5.C1[qLG, cP[1]]; P5.C1[qW, cP[2]]; P5U.DeleteCell[c]};
qRILF =>
IF TRUE THEN
BEGIN
P5.C1[qLL, cP[1]]; P5.C2[qRF, cP[2], cP[3]];
P5U.DeleteCell[c];
END;
ENDCASE => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Peep3: PROC =
BEGIN -- sprinkle DUPs
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
state: PeepState;
canSlide: BOOLFALSE;
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 ← TRUE;
IF bInst = cInst THEN
replace load,load with load,DUP
SELECT cInst FROM
qLL, qLG, qLI =>
IF cP[1] = bP[1] THEN {P5.C0[qDUP]; P5U.DeleteCell[c]; canSlide ← FALSE};
qRIL, qRIG, qRILL, qRIGL =>
IF cP[1] = bP[1] AND cP[2] = bP[2] THEN
{P5.C0[qDUP]; P5U.DeleteCell[c]; canSlide ← FALSE};
ENDCASE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
Peep4: PROC =
BEGIN -- PUTs and PUSHs, RF and WF to RSTR and WSTR
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
state: PeepState;
canSlide: BOOLFALSE;
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] = bP[1] THEN
IF cP[1] IN LocalPutSlots THEN
{cb[b].inst ← qPL; P5U.DeleteCell[c]}
ELSE {CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qPUSH =>
IF bInst = qSL AND bP[1] IN LocalPutSlots THEN
{cb[b].inst ← qPL; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qLG =>
IF bInst = qSG AND cP[1] = bP[1] THEN
{CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qRIL =>
IF bInst = qWIL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN
{CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qRILL =>
IF bInst = qWILL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN
{CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qRIGL =>
IF bInst = qWIGL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN
{CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]}
ELSE canSlide ← TRUE;
qRF, qWF, qRFL, qWFL =>
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,
qRFL => qRSTRL,
ENDCASE => qWSTRL), cP[1]*2+position/8];
P5U.DeleteCell[c];
END;
ENDCASE => canSlide ← TRUE
ELSE canSlide ← TRUE;
END;
ENDCASE => canSlide ← TRUE;
END; -- of OPEN state
ENDCASE => canSlide ← FALSE; -- of WITH
ENDLOOP;
END;
NonWS: ARRAY [FOpCodes.qWS..FOpCodes.qWSD] OF BYTE = [
FOpCodes.qW, FOpCodes.qWF, FOpCodes.qWD];
Peep5: PROC =
BEGIN -- put doubles back, eliminate EXCH preceding commutative operator
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
state: PeepState;
canSlide: BOOLFALSE;
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;
qADD, qMUL, qAND, qOR, qXOR =>
IF bInst = qEXCH THEN P5U.DeleteCell[b] ELSE GO TO Slide;
qWS, qWSF, qWSD =>
IF bInst = qEXCH AND ~NextIsPush[c] THEN
{P5U.DeleteCell[b]; cc.inst ← NonWS[cInst]}
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;
ENDCASE => GO TO Slide;
EXITS
Slide => canSlide ← TRUE;
END; -- of OPEN state
jump =>
BEGIN
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;
FOR next ← NextInteresting[c], NextInteresting[next] WHILE next # CCNull DO
WITH cb[next] SELECT FROM
code => IF ~realinst AND inst = FOpCodes.qPUSH THEN RETURN [TRUE]
ELSE EXIT;
label => NULL;
ENDCASE => EXIT;
ENDLOOP;
IF (next←NextInteresting[cb[c].destlabel]) # CCNull THEN
WITH cb[next] SELECT FROM
code => IF ~realinst AND inst = FOpCodes.qPUSH THEN RETURN [TRUE];
ENDCASE;
RETURN [FALSE]
END;
NextIsPush: PROC [c: CCIndex] RETURNS [BOOL] =
BEGIN -- c is conditional jump; TRUE if PUSH follows on either branch
FOR next: CCIndex ← NextInteresting[c], NextInteresting[next] WHILE next # CCNull DO
WITH cb[next] SELECT FROM
code => IF ~realinst AND inst = FOpCodes.qPUSH THEN RETURN [TRUE]
ELSE EXIT;
label => NULL;
ENDCASE => EXIT;
ENDLOOP;
RETURN [FALSE]
END;
CommuteCells: 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;
Peep6: PROC =
BEGIN -- store double/load double, INC and DEC, MUL to SHIFT etc
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
canSlide: BOOLFALSE;
state: PeepState;
negate: BOOL;
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 SlidePeepState1[@state, LOOPHOLE[ci]]
ELSE InitParameters[@state, LOOPHOLE[ci], bc];
canSlide ← FALSE;
SELECT cInst FROM
qLLD =>
IF bInst = qSLD AND cP[1] = bP[1] THEN
BEGIN
CPtr.codeptr ← b;
IF cP[1] IN LocalPutSlots THEN
{P5.C1[qSL, cP[1]+1]; P5.C1[qPL, cP[1]]; P5.C0[qPUSH]; Delete2[b,c]}
ELSE {P5.C0[qPUSH]; P5.C0[qPUSH]; P5U.DeleteCell[c]};
END
ELSE GO TO Slide;
qLGD =>
IF bInst = qSGD AND cP[1] = bP[1] THEN
{CPtr.codeptr ← b; P5.C0[qPUSH]; P5.C0[qPUSH]; P5U.DeleteCell[c]}
ELSE GO TO Slide;
qADD, qSUB =>
IF bInst = qLI THEN
BEGIN
SELECT LOOPHOLE[bP[1], INTEGER] FROM
0 => Delete2[b,c];
1 => IF cInst = qADD THEN {cb[c].inst ← qINC; P5U.DeleteCell[b]};
-1 => IF cInst = qSUB THEN {cb[c].inst ← qINC; P5U.DeleteCell[b]};
ENDCASE => GO TO Slide;
END
ELSE IF bInst = qNEG THEN
{cb[c].inst ← IF cInst = qADD THEN qSUB ELSE qADD; P5U.DeleteCell[b]}
ELSE GO TO Slide;
qSHIFT =>
IF bInst = qLI THEN
SELECT bP[1] FROM
1 => {cb[c].inst ← qDBL; P5U.DeleteCell[b]};
0 => Delete2[b,c];
ENDCASE => GO TO Slide
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[qDUP]; P5.C0[qDBL]; P5.C0[qADD]; 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[qDUP]; P5.C0[qDBL]; P5.C0[qADD]; D2[]};
ENDCASE =>
BEGIN
powerOf2: BOOL;
log: CARDINAL;
[powerOf2, log] ← Log2[LOOPHOLE[bP[1]]];
IF powerOf2 THEN {P5.LoadConstant[log]; P5.C0[qSHIFT]; D2[]}
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 PrincOpsUtils;
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;
Peep7: PROC =
BEGIN -- find special jumps
OPEN FOpCodes;
ci: CCIndex;
next: CCIndex ← start;
jstate: JumpPeepState;
UNTIL (ci ← next) = CCNull DO
next ← NextInteresting[ci];
WITH cb[ci] SELECT FROM
jump =>
BEGIN OPEN jstate;
InitJParametersBC[@jstate, LOOPHOLE[ci]];
SELECT jtype FROM
JumpE =>
IF bInst = qLI AND bP[1] = 0 THEN {jtype ← ZJumpE; P5U.DeleteCell[b]};
JumpN =>
IF bInst = qLI AND bP[1] = 0 THEN {jtype ← ZJumpN; P5U.DeleteCell[b]};
ENDCASE;
END; -- of OPEN jstate
ENDCASE; -- of WITH
ENDLOOP;
END;
END.