Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/old/kcc/ccjskp.c
There are 8 other files named ccjskp.c in the archive. Click here to see a list.
/*
** ccjskp - KCC peephole optimization for skips and jumps
** module created by David Eppstein / Stanford University / 12 Jun 85
*/
#include "ccgen.h"
extern pcode before(), after();
typedef struct SYMBOL *label;
/*
** See if currently emitted code will be dead.
**
** There are three cases (yes the third one actually happens):
** (1) The last op was an unskipped JRST, i.e. an unconditional jump
** (2) The last op was an unskipped POPJ, i.e. an unconditional return
** (3) The last op was an IFIW, i.e. we're in a switch jump table
*/
int safejump (p)
pcode p;
{
if (p != NULL && optimize) switch (p->pop) {
case JRST: case POPJ: case IFIW: /* jump, return, or jump table? */
return !prevskips (p); /* yes, make sure not skippable over */
}
return 0; /* can't see or not jump, fail */
}
/*
** See if operation can possibly affect following instructions
**
** It can't if it's a JRST, it's a POPJ, or its OPSKIP field is SKPA
** and it skips to an operation that can't affect the stream.
*/
dropsout (p)
pcode p;
{
if (p == NULL) return 0;
if (p->pop == JRST || p->pop == POPJ) return 1;
if ((p->pop & OPSKIP) != SKPA) return 0;
if ((p = after (p)) == NULL || (p = after (p)) == NULL) return 0;
return dropsout (p);
}
/*
** Remove a jump instruction
**
** Actually this removes any instruction, but it is necessary to use if
** the instruction might be a jump so the label refcount can be maintained.
*/
void dropjump (p)
pcode p;
{
if ((p->ptype & ADRMODE) == MINDEXED) reflabel (p->pptr, -1);
p->pop = NOP; /* drop the instruction */
fixprev(); /* fix up previous */
}
/*
** Invert an imbedded skip
**
** Takes a skip instruction in the peephole buffer and makes the code there
** skip on the opposite condition. No new code is emmited (unlike makeskip()).
** Checks to make sure skip can't be itself skipped over.
*/
int invskip (p)
pcode p;
{
int r;
pcode q, b;
if (p == NULL) return 0; /* nothing to invert */
if (!isskip(p->pop)) return 0;
if (p->pop == CAI+ISSKIP+SKPLE && p->ptype == RCONST+SKIPPED &&
(q = before (p)) != NULL && q->ptype == RCONST && q->preg == p->preg &&
q->pop == CAI+ISSKIP+SKPL && q->pvalue == p->pvalue - 1) {
q->pop = CAI+ISSKIP+SKPE; /* invert CAIL R,n / CAILE R,n+1 */
p->pop = CAI+ISSKIP+SKPN; /* to CAIE R,n / CAIN R,n+1 */
return 1;
}
r = revop(p->pop);
if (!(r & OPSKIP)) { /* was SKPA, now no skip at all */
r &=~ ISSKIP; /* so don't think of it as a skip */
if (r == TRN) { /* was TRNA, don't need to check */
p->pop = NOP; /* if skipped, just drop entirely */
fixprev(); /* be careful, might have been prev */
return 1; /* that's all for now gone TRNA */
}
if ((q = before (p)) != NULL && (q->pop & OPSKIP) == SKPA) {
if (!invskip (before (q))) return 0; /* two unflippable SKPAs */
swappseudo (p, q); /* flipped before, now them */
return 1; /* win win */
}
}
if (!prevskips (p)) {
p->pop = r; /* single skip, invert it */
return 1; /* return success */
}
/* look for three-word flip from double comparison */
if (p->ptype != REGIS || !(p->pop & CMPSKIP) || (p->pop & OPCODE) != CAM ||
(q = before (p)) == NULL ||
(b = before (q)) == NULL || b->pop != (p->pop ^ EQSKIP) ||
b->ptype != REGIS || b->preg != p->preg || b->pr2 != p->pr2) return 0;
/* have a doubleword compare, invert the whole thing */
q->pop = revop (q->pop);
p->pop = revop (b->pop);
b->pop = r;
return 1;
}
/*
** Turn CAIx R,0 into something better
**
** The safechange argument is zero if it might be part of a switch
** (in which case we can't safely change the value in the reg).
*/
void foldskip (p, safechange)
pcode p;
{
pcode q;
if (p == NULL || !optimize) return;
/*
** fold: MOVE S,x
** ADD S,y
** CAMN R,S
**
** into: SUB R,x
** SUB R,y
** CAIN R,0
**
** (only for CAMN and CAME, to avoid wrap problems).
*/
if ((p->pop == CAM+ISSKIP+SKPE || p->pop == CAM+ISSKIP+SKPN) &&
p->ptype == REGIS)
for (q = before (p); q != NULL; q = before (q)) {
if (prevskips (q) || q->preg != p->pr2) break;
switch (q->pop) {
case ADD: case SUB:
q->preg = p->preg; /* swap adds across to other reg */
q->pop ^= (ADD ^ SUB); /* making them subtracts instead */
continue;
case MOVE: case MOVN:
q->preg = p->preg; /* same for MOVE and MOVN */
q->pop = (q->pop == MOVE? SUB : ADD); /* turned into SUB and ADD */
p->pop ^= (CAM ^ CAI); /* make immediate comparison */
p->ptype = RCONST; /* against number */
p->pvalue = 0; /* number is zero */
}
break; /* escape loop if not explicit cont */
}
if ((p->pop & OPCODE) != CAI) return; /* must be CAIx */
q = before(p); /* look before it */
if (q != NULL && q->ptype == REGIS /* !prevskips */ && q->preg == p->preg
&& q->pop == MOVE && safechange) {
/*
** fold: MOVE R,S
** CAIx R,c
**
** into: CAIx S,c
*/
p->preg = q->pr2; /* flatten tested register */
q->pop = NOP; /* flush useless move */
q = before(q); /* try for more optimizations */
}
if (q->preg == p->preg && q->ptype == IMMED && safechange)
switch(q->pop) {
case SUB:
if (!unsetz (q)) break;
case ADD:
/*
** fold: ADDI R,n
** CAIx R,m
**
** into: CAIx R,m-n
*/
p->pvalue -= q->pvalue;
q->pop = NOP; /* flush folded addition */
q = before(q); /* look for more before it */
}
/*
** fold: CAIGE R,1
** into: CAIG R,0
*/
if ((p->ptype & ADRMODE) != RCONST) return; /* rest of opts need numbers */
switch (p->pop & OPSKIP) {
case SKPG: case SKPLE: /* skip that can be adjusted up? */
if (p->pvalue == -1 || p->pvalue == -2) { /* worthwhile to do it? */
p->pvalue++; /* yes, increment value */
p->pop ^= EQSKIP; /* and adjust skip to match */
}
break;
case SKPL: case SKPGE: /* skip that can be adjusted down? */
if (p->pvalue == 1 || p->pvalue == 2) { /* worthwhile to do it? */
p->pvalue--; /* yes, decrement value */
p->pop ^= EQSKIP; /* and adjust skip to match */
}
break;
}
/*
** Fold remaining comparisons against one into AOSx which will
** later become AOJx. We make AOS R,R rather than AOS R so we
** don't confuse the rest of code generation too badly.
**
** All optimizations after this one can safely assume that the
** value being compared against is zero.
*/
switch (p->pvalue) {
case 1:
if (!safechange) return; /* not for switch you don't */
p->pop ^= (CAI ^ SOS); /* make SOSx */
p->ptype ^= (RCONST ^ REGIS); /* from and to register */
p->pr2 = p->preg; /* same register */
return; /* that's all */
case -1:
if (!safechange) return; /* not for switch you don't */
p->pop ^= (CAI ^ AOS); /* make AOSx */
p->ptype ^= (RCONST ^ REGIS); /* from and to register */
p->pr2 = p->preg; /* same register */
return; /* that's all */
case 0: break; /* zero is ok to continue with */
default: return; /* anything else we can't handle */
}
/*
** The remaining optimizations fold a test against zero with
** the previous instruction.
*/
if (q->preg != p->preg) {
if (q->pop == IDIV && q->preg + 1 == p->preg && safechange &&
q->ptype == IMMED /* !prvsk */ && ((q->pvalue-1)&q->pvalue) == 0) {
/*
** fold: IDIVI R-1,2^n
** CAIx R,0
**
** into: TRNx R,2^n-1
*/
switch (p->pop & OPSKIP) {
case SKPE:
case SKPN:
p->pop ^= (CAI ^ TRN);
p->preg = q->preg;
p->ptype = RCONST;
p->pvalue = q->pvalue - 1;
q->pop = NOP;
q = before(q); /* now look at before the IDIVI */
if (q->ptype == REGIS /* !prevskips */ && q->pop == MOVE &&
q->preg == p->preg) {
p->preg = q->pr2;
q->pop = NOP; /* flatten failed changereg() */
}
}
}
return;
}
if (prevskips (q)) return;
switch (q->pop) {
case AND:
if (!safechange) return;
switch (p->pop & OPSKIP) {
case SKPE:
case SKPN:
/*
** fold: AND R,mask
** CAIE R,0
**
** into: TDNE R,mask
*/
if (q->ptype == IMMED) {
q->ptype = RCONST;
q->pop = p->pop ^ (CAI ^ TRN);
} else q->pop = p->pop ^ (CAI ^ TDN);
break;
default: return;
}
break;
case MOVE:
/*
** fold: MOVE R,addr
** CAIx R,0
**
** into: SKIPx R,addr
*/
q->pop = p->pop ^ (CAI ^ SKIP);
break;
case ADD:
if (q->ptype != IMMED) return;
q->pvalue = - q->pvalue;
case SUB:
/*
** fold: SUB R,addr
** CAIN R,0
**
** into: CAMN R,addr
**
** (only for CAMN or CAME, not other comparisons)
*/
if (p->pop != CAI+ISSKIP+SKPE && p->pop != CAI+ISSKIP+SKPN) return;
q->pop = p->pop; /* make comparison */
if (q->ptype & IMM) q->ptype &=~ IMM; /* immediate uses CAI form */
else q->pop ^= (CAM ^ CAI); /* memory uses CAM form */
break;
case AOS: case SOS:
/*
** fold: AOS R,addr
** CAIx R,0
**
** into: AOSx R,addr
*/
q->pop |= (p->pop &~ OPCODE);
break;
default: return;
}
/*
** All the defaults in the previous switch should be return statements,
** so if we made it through we must have made a fold. We should therefore
** flush the CAIx so we don't have two skips in a row.
*/
p->pop = NOP; /* flush it */
fixprev(); /* make sure previous valid */
}
/*
** Turn a jump into an immediate compare against zero.
**
** Assumes there is one instruction between the jump and its
** label; if only zero the resulting skip should be reversed.
** Doesn't update SKIPPED in following opcodes.
*/
static void
jumptoskip (p)
pcode p;
{
if ((p->ptype &~ SKIPPED) == MINDEXED) switch (p->pop & OPCODE) {
case JRST:
if (invskip (before (p))) { /* can flip previous skips */
dropjump (p); /* so having done it just drop jump */
return;
}
reflabel (p->pptr, -1); /* fix up reference counts */
p->pop = TRN+ISSKIP+SKPA; /* now turn it into a TRNA */
p->ptype ^= (MINDEXED ^ ONEREG); /* no address */
p->preg = 0; /* no register either */
return;
case JUMP:
reflabel (p->pptr, -1); /* fix up reference counts */
p->pop ^= (CAI ^ JUMP ^ ISSKIP); /* make CAIx */
p->ptype ^= (MINDEXED ^ RCONST); /* immediate compare */
p->pvalue = 0; /* against zero */
return;
case AOJ:
reflabel (p->pptr, -1); /* fix up reference counts */
p->pop ^= (AOS ^ AOJ ^ ISSKIP); /* make AOSx */
p->ptype ^= (MINDEXED ^ REGIS); /* reg to reg */
p->pr2 = p->preg; /* both same reg */
return;
case SOJ:
reflabel (p->pptr, -1); /* fix up reference counts */
p->pop ^= (SOS ^ SOJ ^ ISSKIP); /* make SOSx */
p->ptype ^= (MINDEXED ^ REGIS); /* reg to reg */
p->pr2 = p->preg; /* both same reg */
return;
}
}
/*
** Pull JUMPx across skips
**
** Sometimes it can improve code to move a JUMPx, AOJx, or SOJx from one
** side of a set of cascaded skips to the other. We have to be careful
** though in rearranging this sort of thing that we don't get illegal
** memory references or indirection loops.
*/
void crossjump (lab)
label lab;
{
int regok[NREGS], i;
pcode q;
/*
** fold: JUMPE R,L1
** (any number of skips)
** JRST L2
** JRST L1
**
** into: (the same skips)
** JUMPN R,L2
** JRST L1
*/
for (i = 0; i < NREGS; i++) regok[i] = 1; /* reg not yet seen */
if (previous->pop != JRST) return; /* must be a jump here */
for (q = before (previous); q != NULL; q = before (q))
switch (q->pop & OPCODE) {
case AOJ: case SOJ:
if (regok[q->preg] < 0) return; /* not safe to commute */
case JUMP:
if (q->pptr != lab || !regok[q->preg] || prevskips (q)) return;
previous->preg = q->preg; /* else copy register to jump on */
previous->pop = revop (q->pop); /* invert jump cond */
dropjump (q); /* drop original JUMPx */
return; /* that's all */
default:
if (!isskip (q->pop)) return;
regok[q->preg] = 0;
case TRN: case TDN: case CAI: case CAM:
if (q->ptype & IND) return; /* careful about @ loops */
switch (q->ptype & ADRMODE) { /* look at type of op */
case PFLOAT: case RCONST: case ONEREG: break; /* no 2nd reg ops */
default: regok [q->pindex & 017] = 0; /* MINDEXED, REGIS, BYTEPOINT */
}
if (regok[q->preg]) regok[q->preg] = -1; /* not safe for AOJx */
continue;
}
}
/*
** Common optimizations for labels and jumps
**
** Called either when about to emit a jump to the given label, or when about
** to emit the label itself. There are some things we can do in optlab()
** that we can't do here, because (for instance) we don't want to turn a
** jump two before another to the same place into a TRNA to the jump.
*/
void foldjump (lab)
label lab;
{
pcode q, b;
int r;
if (!optimize || previous == NULL || !oneinstr(previous) ||
(q = before(previous)) == NULL || (b = before(q)) == NULL) return;
if (q->pop == JRST && q->pptr == lab && !(q->ptype & IND) && invskip(b)) {
/*
** fold: skip
** JRST n
** op
** JRST n
**
** into: reverse skip
** op
** JRST n
*/
dropjump(q); /* already flipped skip, drop jump */
setskip (previous); /* op is now skipped over */
if (previous->pop == MOVN && b->preg == previous->preg && !prevskips(b)
&& (b->pop == SKIP+ISSKIP+SKPG || b->pop == SKIP+ISSKIP+SKPGE) &&
(sameaddr (b, previous, 0) || (previous->ptype == SKIPPED+REGIS &&
previous->preg == previous->pr2))) {
/*
** fold: SKIPGE 1,x
** MOVN 1,1
**
** into: MOVM 1,x
*/
b->pop = MOVM; /* make MOVM */
previous->pop = NOP; /* drop MOVN */
fixprev(); /* fix up to point to last op (MOVM) */
}
} else if (isskip (q->pop) && b->pop == JRST && b->pptr == lab &&
invskip (before (b))) {
/*
** fold: skip1
** JRST n
** skip2
** op
** JRST n
**
** into: reverse skip1
** reverse skip2
** JRST n
** op
** JRST n
*/
q->pop = revop(q->pop); /* reverse the second skip */
setskip (q); /* skip now will be skipped over */
swappseudo(b, q); /* switch the skip and the jump */
clrskip (previous); /* op no longer skipped over */
}
crossjump (lab); /* pull JUMPx across skips */
}
/*
** Turn non-skip op into a skip
**
** I.e. MOVE becomes SKIPA. Works even if op is skipped over
** (caller must check for that case). Again, afters are not set SKIPPED.
*/
static int
newskip (p)
pcode p;
{
pcode q;
if (p != NULL) switch (p->pop) {
case SUB:
if ((p->ptype &~ SKIPPED) != IMMED || p->pvalue != 1) break;
p->ptype ^= (IMMED ^ REGIS);
p->pr2 = p->preg;
case SOS:
p->pop = SOS+ISSKIP+SKPA;
return 1;
case ADD:
if ((p->ptype &~ SKIPPED) != IMMED || p->pvalue != 1) break;
p->ptype ^= (IMMED ^ REGIS);
p->pr2 = p->preg;
case AOS:
p->pop = AOS+ISSKIP+SKPA;
return 1;
case IOR:
if (p->ptype & IMM) {
p->pop = TRO+ISSKIP+SKPA;
p->ptype &=~ IMM;
} else p->pop = TDO+ISSKIP+SKPA;
return 1;
case XOR:
if (p->ptype & IMM) {
p->pop = TRC+ISSKIP+SKPA;
p->ptype &=~ IMM;
} else p->pop = TDC+ISSKIP+SKPA;
return 1;
case SETZ:
if ((p->ptype &~ SKIPPED) != ONEREG) break;
p->pop = TDZ+ISSKIP+SKPA;
p->ptype ^= (ONEREG ^ REGIS);
p->pr2 = p->preg;
return 1;
case SETO: case MOVN: case MOVE:
if (!unsetz (p) || p->ptype == IINDEXED) break; /* no XSKIPAI */
p->pop = SKIP+ISSKIP+SKPA;
if ((p->ptype &~ SKIPPED) == REGIS && (q = before (p)) != NULL &&
q->preg == p->pr2 && !prevskips (q)) switch (q->pop & OPCODE) {
case SKIP: case AOS: case SOS:
/*
** fold: SKIPx S,x
** SKIPA R,S
**
** into: SKIPx R,x
*/
q->pop = revop (q->pop); /* invert skip */
q->preg = p->preg; /* set reg */
p->pop = NOP; /* drop extra skip */
fixprev(); /* fix up previous */
}
return 1;
}
return 0;
}
/*
** Turn skip back into non-skip
** Undoes the actions of newskip(), and turns off conditional skips.
**
** Safe to be called on non-skip ops like JRST and POPJ.
*/
void unskip (p)
pcode p;
{
pcode q;
if (!isskip (p->pop)) return; /* be safe for JUMPx */
switch (p->pop &= OPCODE) {
case SOS:
if ((p->ptype &~ SKIPPED) != REGIS || p->pr2 != p->preg) return;
p->pop = SUB; /* SOSA R,R */
p->ptype ^= (REGIS ^ IMMED); /* becomes SUBI R,1 */
p->pvalue = 1;
return;
case AOS:
if ((p->ptype &~ SKIPPED) != REGIS || p->pr2 != p->preg) return;
p->pop = ADD; /* AOSA R,R */
p->ptype ^= (REGIS ^ IMMED); /* becomes ADDI R,1 */
p->pvalue = 1;
return;
case TRO:
p->ptype |= IMM;
case TDO:
p->pop = IOR;
return;
case TRC:
p->ptype |= IMM;
case TDC:
p->pop = XOR;
return;
case TDZ:
if ((p->ptype &~ SKIPPED) != REGIS || p->pr2 != p->preg) return;
p->pop = SETZ; /* TDZA R,R */
p->ptype ^= (REGIS ^ ONEREG); /* becomes SETZ R, */
return;
case SKIP:
p->pop = MOVE;
if ((p->ptype &~ SKIPPED) != IMMED || p->pvalue != -1) return;
p->pop = SETO;
p->ptype ^= (IMMED ^ ONEREG);
return;
case TRN: case TDN: case TLN: case CAI: case CAM: /* no-ops */
p->pop = NOP; /* flush it all the way */
fixprev(); /* fix up previous */
unskip (before (p)); /* make sure no spurious skippage */
}
/* default is safe, just op with no skip part */
}
/*
** Optimize code in front of label
**
** If we know the label is coming after the next instruction, we can
** make several changes, mostly turning jumps into skips, that improve
** code and may make it possible not to emit the label.
*/
void optlab (lab)
label lab;
{
int op;
pcode p, q, b, bb;
if (!optimize) return;
/* fold useless jumps and preceeding skips into nothing */
if ((previous->pop == JRST || (previous->pop & OPCODE) == JUMP) &&
previous->pptr == lab && !(previous->ptype & IND)) {
dropjump (previous); /* drop the jump or skip */
unskip (previous); /* disable the skip before it */
}
p = before(previous);
if (p != NULL && oneinstr(previous) && p->pop == CAI+ISSKIP+SKPE &&
p->ptype == RCONST && (q = before(p)) != NULL && q->pop == JRST &&
q->pptr == lab && (b = before(q)) != NULL && !prevskips (b))
switch(b->pop) {
/*
** fold: CAIN R,x
** JRST lab
** CAIE R,x+1
** instr
** lab:
**
** into: CAIL R,x
** CAILE R,x+1
** instr
** lab:
*/
case AOS+ISSKIP+SKPN:
if (p->pvalue == 1) {
b->pop = AOS+ISSKIP+SKPL;
dropjump(q);
p->pop = CAI+ISSKIP+SKPLE;
setskip (p);
}
break;
case SKIP+ISSKIP+SKPN:
if (p->pvalue == 1) {
b->pop = SKIP+ISSKIP+SKPL;
dropjump(q);
p->pop = CAI+ISSKIP+SKPLE;
setskip (p);
}
break;
case SOS+ISSKIP+SKPN:
if (p->pvalue == 1) {
b->pop = SOS+ISSKIP+SKPL;
dropjump(q);
p->pop = CAI+ISSKIP+SKPLE;
setskip (p);
}
break;
case CAI+ISSKIP+SKPN:
if (b->ptype != RCONST) break;
if (b->pvalue + 1 == p->pvalue) {
b->pop = CAI+ISSKIP+SKPL;
dropjump(q);
p->pop = CAI+ISSKIP+SKPLE;
setskip (p);
} else if (b->pvalue == p->pvalue + 1) {
b->pop = CAI+ISSKIP+SKPL;
b->pvalue--; /* note foldskip unsafe here! */
dropjump(q); /* might be in a recursive casejump */
setskip (p);
p->pop = CAI+ISSKIP+SKPLE;
p->pvalue++;
}
} /* end switch(b->pop) */
foldjump (lab); /* common optimizations with JRST */
if (!oneinstr (previous) || (p = before (previous)) == NULL) return;
/* fold JUMPx R,lab / instr / lab:: into CAIx R,0 / instr */
if (p->pptr == lab) {
jumptoskip (p); /* make into skip */
if (isskip (p->pop)) setskip (previous); /* set instr skipped */
crossjump (lab); /* now retry pulling JUMPx across */
p = before (previous); /* fix up again */
}
/*
** Remaining optimizations work for jumps over two instructions.
** If we don't have that, give up.
*/
if ((q = before (p)) == NULL || (q->ptype & ADRMODE) != MINDEXED ||
q->pptr != lab) return; /* make sure some jump to lab */
/*
** fold: JUMPx R,$n
** MOVE S,R
** op
** $n::
**
** into: SKIPx S,R
** op
*/
if (p->pop == MOVE && p->ptype == REGIS && q->preg == p->pr2 &&
!prevskips (q)) switch (q->pop & OPCODE) {
case JUMP:
p->pop = q->pop ^ (JUMP ^ SKIP ^ ISSKIP);
dropjump (q);
setskip (previous);
optlab (lab); /* try again */
return; /* tail recursively */
case AOJ:
p->pop = q->pop ^ (AOJ ^ AOS ^ ISSKIP);
dropjump (q);
setskip (previous);
optlab (lab); /* try again */
return; /* tail recursively */
case SOJ:
p->pop = q->pop ^ (SOJ ^ SOS ^ ISSKIP);
dropjump (q);
setskip (previous);
optlab (lab); /* try again */
return; /* tail recursively */
}
/* A couple of these deal with skipping over MOVEMs */
if (previous->pop == MOVEM && p->pop == MOVE && p->preg == previous->preg)
{
if (p->ptype == IMMED && p->pvalue == 1 && q->pop == SOJ+SKPN &&
!prevskips (q) && changereg (p->preg, q->preg, before (q))) {
/*
** fold: SOJN R,$x
** MOVEI S,1
** MOVEM S,y
** $x::
**
** into: CAIN R,1
** MOVEM R,y
*/
dropjump (q); /* flush SOJN */
p->pop = CAI+ISSKIP+SKPN; /* make skip comparison */
p->ptype = RCONST; /* immediate built in to CAI */
p->pvalue = 1; /* against one */
setskip (previous); /* movem is now skipped over */
optlab (lab); /* try again */
return; /* tail recursively */
}
/*
** fold: MOVEM R,x
** JUMPy S,lab
** MOVE T,w
** MOVEM T,x
**
** into: CAIy S,0
** MOVE R,y
** MOVEM R,x
*/
for (b = q; b != NULL; b = before (b)) if (b->pop == MOVEM) break;
for (bb = after(b); b != NULL && bb != NULL && bb != p; bb = after(bb))
switch (bb->pop & OPCODE) {
case MOVE: case ADD: case AOJ: case SOJ: case SKIP:
case SETZ: case SETO: case IOR: case LDB:
if (bb->preg == b->preg) b = NULL; /* unsafe rchange, flush */
case TLN: case TDN: case TRN: case CAI: case CAM: case JUMP: case JRST:
continue; /* safe or not, try again or break */
default: b = NULL; /* not one we know */
}
if (b != NULL && sameaddr (b, previous, 0)) {
jumptoskip (q); /* turn jump into skip */
p->preg = previous->preg = b->preg; /* set registers */
setskip (p); /* MOVE is now skipped over */
b->pop = NOP; /* drop first MOVEM */
if (q->pop == TRN+ISSKIP+SKPA && invskip (before (q)))
q->pop = NOP; /* fold TRNA into previous */
else foldskip (q, 0); /* else safely fold ex-JUMP */
return;
}
} /* end if MOVE and MOVEM */
/*
** fold: (skips)
** JRST lab
** MOVE R,y
** instr
**
** into: (inverse skips)
** SKIPA R,y
** TRNA
** instr
*/
if (q->pop != JRST || !newskip (p)) return;
if (!invskip (before (q))) {
unskip (p); /* can't flip, undo changes */
return; /* and give up */
}
reflabel (lab, -1); /* drop jump */
setskip (p); /* p skipped */
q->pop = TRN+ISSKIP+SKPA; /* make TRNA */
q->ptype = ONEREG; /* no mem ref */
setskip (q); /* q skipped */
swappseudo (p, q); /* swap TRNA and new SKIPA */
setskip (previous); /* previous skipped */
if (!invskip (q)) return; /* rest depends on flipping SKIPA */
p->pop = NOP; /* if can flip, no TRNA */
/*
** fold: SKIPA R,x
** TDOA R,$BYTE
** IOR R,$BYTE
**
** into: MOVE R,x
** IOR R,$BYTE
*/
if (previous->pop != IOR || (q = before (previous)) == NULL ||
q->pop != TDO+ISSKIP+SKPA || !sameaddr (q, previous, 0)) return;
unskip (before (q)); /* turn prev skip off */
q->pop = NOP; /* drop TDOA */
clrskip (previous); /* IOR not skipped over anymore */
}
/*
** Get rid of jump so can replace it with jumped-to label
**
** Called when we know there will only be one more instruction between
** here and the label, but we can't rely on later optimization because
** we want to emit another label here.
**
** Returns 1 or 0 depending on whether made successful skip.
** In neither case changes SKIPPED attribute of succeeding instrs.
*/
int unjump (lab)
label lab;
{
pcode p;
if (previous == NULL || previous->pptr != lab) return 0;
switch (previous->pop & OPCODE) {
case JRST:
dropjump (previous); /* drop it all the way out */
return 1;
case JUMP: case AOJ: case SOJ:
jumptoskip (previous); /* make into CAIx */
previous->pop = revop (previous->pop); /* with opposite parity */
return 1; /* let optlab() take care of rest */
default:
return 0;
}
}
/*
** Attempt to get rid of a TRNA.
**
** Folds it into instructions ahead of it in the buffer.
** This is called late, by realcode(), to avoid confusion
** in earlier parts of the peepholer.
*/
foldtrna (p)
pcode p;
{
pcode q, a;
if (p == NULL || p->pop != TRN+ISSKIP+SKPA || (q = after (p)) == NULL ||
(q->pop != JRST && q->pop != POPJ && (q->pop & OPSKIP) != SKPA) ||
(a = after (q)) == NULL || !newskip (a)) return 0; /* no good */
/*
** fold: TRNA
** JRST $x
** MOVE R,y
**
** into: SKIPA R,y
** JRST $x
*/
unskip (q); /* turn SKIPA over op into MOVE */
setskip (a); /* op that skipped TRNA now skips it */
swappseudo (q, a); /* switch the jump and new skip */
p->pop = NOP; /* TRNA disappears */
return 1; /* tell realcode() we won */
}
/*
** Fold test type instruction into previous SKIPA+MOVE
*/
inskip (p)
pcode p;
{
pcode q, b;
int skop, compl;
if (p->ptype != REGIS) return; /* must be unskipped register op */
switch (p->pop) { /* see what we want to fold back up */
case AND: skop = TDZ; compl = 1; break; /* SKIPA+MOVE+AND => TDZA+AND */
case IOR: skop = TDO; compl = 0; break; /* SKIPA+MOVE+IOR => TDOA+IOR */
case XOR: skop = TDC; compl = 0; break; /* SKIPA+MOVE+XOR => TDCA+XOR */
default: break; /* can't handle anything else */
}
/* look for SKIPA and MOVE (with right registers) before op */
/* we save the unsetz for last because it has side effects */
if ((q = before (p)) == NULL || (q->preg != p->pr2 && q->preg != p->preg)
|| (b = before (q)) == NULL || b->pop != SKIP+ISSKIP+SKPA ||
(compl && b->ptype != IMMED+SKIPPED) || b->preg != q->preg ||
!unsetz (q)) return;
/* found them, perform the fold */
b->pop = skop + ISSKIP + SKPA; /* make always skipping op for SKIPA */
if (b->ptype & IMM) { /* if immediate quantity */
b->ptype &=~ IMM; /* make RCONST rather than IMMED */
b->pop = immedop (b->pop); /* and use built-in-immed op */
}
if (compl) b->pvalue = ~ b->pvalue; /* complement mask if TDZA for AND */
q->pop = p->pop; /* and non-skip for MOVE (no compl) */
/* see if result is already in right reg; if not, put it there */
if (q->preg == p->pr2 || changereg (p->preg, p->pr2, before (b))) {
b->preg = q->preg = p->preg; /* ok or fixed, change regs */
p->pop = NOP; /* drop now useless op */
fixprev(); /* point again to end of ph buff */
} else {
b->preg = q->preg = p->pr2; /* pre-op val in wrong reg, fix ops */
p->pop = MOVE; /* add MOVE to put in right place */
}
}