home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff384.lzh
/
NorthC
/
Example2.LZH
/
top
/
peep.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-30
|
19KB
|
930 lines
/* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*/
/*
* Peephole optimization routines
*/
#include "top.h"
/*
* ipeep1(ip) - check for changes to the instruction 'ip'
*/
static int
ipeep1(bp, ip)
register BLOCK *bp;
register INST *ip;
{
/*
* clr.l Dn => moveq.l Dn
*/
if (ip->opcode == CLR && ip->src.amode == REG &&
ISD(ip->src.areg) && (ip->flags & LENL)) {
ip->opcode = MOVEQ;
ip->dst = ip->src; /* we'll have two operands now */
ip->src.amode = IMM;
ip->src.disp = 0;
return 1;
}
/*
* move.* #n,Dn => moveq.* #n,Dn
*/
if (ip->opcode == MOVE && ip->src.amode == IMM && ISD(ip->dst.areg) &&
ip->flags == LENL && ip->src.disp >= -128 && ip->src.disp <= 127) {
ip->opcode = MOVEQ;
return 2;
}
/*
* add.x #n, Reg => addq.x #n, Reg
* where 1 <= n <= 8
*/
if (ip->opcode == ADD && ip->src.amode == IMM && ip->dst.amode == REG &&
ip->src.disp >= 1 && ip->src.disp <= 8) {
ip->opcode = ADDQ;
return 3;
}
/*
* sub.x #n, Reg => subq.x #n, Reg
* where 1 <= n <= 8
*/
if (ip->opcode == ADD && ip->src.amode == IMM && ip->dst.amode == REG &&
ip->src.disp >= 1 && ip->src.disp <= 8) {
ip->opcode = SUBQ;
return 4;
}
/*
* movem.x Reg,-(sp) => move.x Reg,-(sp)
*/
if (ip->opcode == MOVEM && ip->src.amode == REG &&
ip->dst.areg == SP && ip->dst.amode == (REGI|DEC)) {
ip->opcode = MOVE;
return 5;
}
/*
* movem.x (sp)+,Reg => move.x (sp)+,Reg
*/
if (ip->opcode == MOVEM && ip->dst.amode == REG &&
ip->src.amode == (REGI|INC) && ip->src.areg == SP) {
ip->opcode = MOVE;
return 6;
}
/*
* add[q] #?,sp
*
* Remove instruction if sp is dead.
*/
if ((ip->opcode == ADDQ || ip->opcode == ADD) && ip->src.amode == IMM &&
ip->dst.amode == REG && ip->dst.areg == SP) {
if (do_dflow && ((ip->live & RM(SP)) == 0)) {
delinst(bp, ip);
s_idel++;
return 7;
}
}
return 0;
}
/*
* peep1(bp) - peephole optimizations with a window size of 1
*
* Returns TRUE if any optimizations were made.
*/
static bool
peep1(bp)
register BLOCK *bp;
{
register INST *ip;
register bool changed = FALSE;
register int pnum;
#ifdef DEBUG
if (debug)
fprintf(stderr, "peep1: ");
#endif
for (; bp != NULL ;bp = bp->next) {
for (ip = bp->first; ip != NULL ;) {
if (pnum = ipeep1(bp, ip)) {
changed = TRUE;
s_peep1++;
#ifdef DEBUG
if (debug)
fprintf(stderr, "%d ", pnum);
#endif
/*
* Start over in case the instruction we
* just looked at got deleted.
*/
ip = bp->first;
} else
ip = ip->next;
}
}
#ifdef DEBUG
if (debug)
fprintf(stderr, "\n");
#endif
return changed;
}
/*
* ipeep2(bp, ip) - look for 2-instruction optimizations at the given inst.
*/
static int
ipeep2(bp, ip)
register BLOCK *bp;
register INST *ip;
{
INST *ni = ip->next; /* the next instruction */
INST *tni; /* "temporary" next inst, for skipping */
/*
* addq #4,sp
* ... stuff that doesn't use SP ...
* move.l ?,-(sp) => move.l ?,(sp)
*/
if (ip->opcode == ADDQ && ip->src.amode == IMM && ip->src.disp == 4 &&
ip->dst.amode == REG && ip->dst.areg == SP) {
tni = ni;
while (do_dflow && !uses(tni, SP)) {
if (tni->next == NULL)
return 0;
tni = tni->next;
}
if (tni->opcode == MOVE && tni->flags == LENL &&
tni->dst.amode == (REGI|DEC) && tni->dst.areg == SP) {
tni->dst.amode = REGI;
delinst(bp, ip);
s_idel++;
return 1;
}
}
/*
* addq #2,sp
* ... stuff that doesn't use SP ...
* move.w ?,-(sp) => move.w ?,(sp)
*/
if (ip->opcode == ADDQ && ip->src.amode == IMM && ip->src.disp == 2 &&
ip->dst.amode == REG && ip->dst.areg == SP) {
tni = ni;
while (do_dflow && !uses(tni, SP)) {
if (tni->next == NULL)
return 0;
tni = tni->next;
}
if (tni->opcode == MOVE && tni->flags == LENW &&
tni->dst.amode == (REGI|DEC) && tni->dst.areg == SP) {
tni->dst.amode = REGI;
delinst(bp, ip);
s_idel++;
return 2;
}
}
/*
* move.x X, Y => move.x X, Y
* tst.x Y ...deleted...
* beq/bne beq/bne
*
* Where Y is not An, because "movea" doesn't set the
* zero flag.
*/
if (bp->last == ni && (bp->bcode == BEQ || bp->bcode == BNE) &&
ip->opcode == MOVE && ni->opcode == TST &&
ip->flags == ni->flags) {
int is_dec = FALSE;
/*
* If pre-decrement is set on the dest. of the move,
* don't let that screw up the operand comparison.
*/
if (ip->dst.amode & DEC) {
is_dec = TRUE;
ip->dst.amode &= ~DEC;
}
if (opeq(&ip->dst, &ni->src)) {
if (ip->dst.amode != REG || ISD(ip->dst.areg)) {
if (is_dec)
ip->dst.amode |= DEC;
delinst(bp, ni);
s_idel++;
return 3;
}
}
if (is_dec)
ip->dst.amode |= DEC;
}
/*
* add[q] #?,sp
* ... stuff that doesn't use SP ...
* unlk An => unlk An
*/
if ((ip->opcode == ADDQ || ip->opcode == ADD) && ip->src.amode == IMM &&
ip->dst.amode == REG && ip->dst.areg == SP) {
tni = ni;
while (do_dflow && !uses(tni, SP)) {
if (tni->next == NULL)
return 0;
tni = tni->next;
}
if (tni->opcode == UNLK) {
delinst(bp, ip);
s_idel++;
return 4;
}
}
/*
* move.x Dm, Dn => move.x Dm, Dn
* move.x Dn, Dm
*/
if ((ip->opcode == MOVE) && (ni->opcode == MOVE) &&
(ip->src.amode == REG) && (ip->dst.amode == REG) &&
(ni->src.amode == REG) && (ni->dst.amode == REG)) {
if (ISD(ip->src.areg) && (ip->src.areg == ni->dst.areg) &&
ISD(ip->dst.areg) && (ip->dst.areg == ni->src.areg)) {
delinst(bp, ni);
s_idel++;
return 5;
}
}
/*
* move.l Am, Dn => move.l Am, Ao
* ... stuff ... ... stuff ...
* move.l Dn, Ao
*
* where "stuff" doesn't set Dn.
*/
if ((ip->opcode == MOVE) && (ip->flags == LENL) &&
(ip->src.amode == REG) && ISA(ip->src.areg) &&
(ip->dst.amode == REG) && ISD(ip->dst.areg)) {
tni = ni;
while (do_dflow && !sets(tni, ip->dst.areg)) {
if ((tni->opcode == MOVE) && (tni->flags == LENL) &&
(tni->src.amode == REG) && ISD(tni->src.areg) &&
(tni->dst.amode == REG) && ISA(tni->dst.areg) &&
(ip->dst.areg == tni->src.areg)) {
/*
* If the intermediate register isn't dead,
* then we have to keep using it.
*/
if ((tni->live & RM(tni->src.areg)) != 0)
return 0;
ip->dst.areg = tni->dst.areg;
delinst(bp, tni);
s_idel++;
return 6;
}
if (tni->next == NULL)
return 0;
tni = tni->next;
}
}
/*
* sub.l #1, Am
* ... stuff ...
* ???.b ..(Am).. => ???.b ..-(Am)..
*
* Nothing in "stuff" can refer to Am.
*/
if ((ip->opcode == SUB) && (ip->flags & LENL) &&
(ip->src.amode == IMM) && (ip->src.disp == 1) &&
(ip->dst.amode == REG) && ISA(ip->dst.areg)) {
int rm = ip->dst.areg;
while (ni != NULL) {
if (ni->src.amode == REGI && ni->src.areg == rm) {
if ((ni->flags & LENB) == 0)
return 0;
ni->src.amode |= DEC;
delinst(bp, ip);
s_idel++;
return 7;
}
if (ni->dst.amode == REGI && ni->dst.areg == rm) {
if ((ni->flags & LENB) == 0)
return 0;
ni->dst.amode |= DEC;
delinst(bp, ip);
s_idel++;
return 7;
}
if (uses(ni, RM(rm)))
return 0;
if (ni->next == NULL)
return 0;
else
ni = ni->next;
}
}
/*
* sub.l #2, Am
* ... stuff ...
* ???.w ..(Am).. => ???.w ..-(Am)..
*
* Nothing in "stuff" can refer to Am.
*/
if ((ip->opcode == SUB) && (ip->flags & LENL) &&
(ip->src.amode == IMM) && (ip->src.disp == 2) &&
(ip->dst.amode == REG) && ISA(ip->dst.areg)) {
int rm = ip->dst.areg;
while (ni != NULL) {
if (ni->src.amode == REGI && ni->src.areg == rm) {
if ((ni->flags & LENW) == 0)
return 0;
ni->src.amode |= DEC;
delinst(bp, ip);
s_idel++;
return 8;
}
if (ni->dst.amode == REGI && ni->dst.areg == rm) {
if ((ni->flags & LENW) == 0)
return 0;
ni->dst.amode |= DEC;
delinst(bp, ip);
s_idel++;
return 8;
}
if (uses(ni, RM(rm)))
return 0;
if (ni->next == NULL)
return 0;
else
ni = ni->next;
}
}
/*
* sub.l #4, Am
* ... stuff ...
* ???.l ..(Am).. => ???.l ..-(Am)..
*
* Nothing in "stuff" can refer to Am.
*/
if ((ip->opcode == SUB) && (ip->flags & LENL) &&
(ip->src.amode == IMM) && (ip->src.disp == 4) &&
(ip->dst.amode == REG) && ISA(ip->dst.areg)) {
int rm = ip->dst.areg;
while (ni != NULL) {
if (ni->src.amode == REGI && ni->src.areg == rm) {
if ((ni->flags & LENL) == 0)
return 0;
ni->src.amode |= DEC;
delinst(bp, ip);
s_idel++;
return 9;
}
if (ni->dst.amode == REGI && ni->dst.areg == rm) {
if ((ni->flags & LENL) == 0)
return 0;
ni->dst.amode |= DEC;
delinst(bp, ip);
s_idel++;
return 9;
}
if (uses(ni, RM(rm)))
return 0;
if (ni->next == NULL)
return 0;
else
ni = ni->next;
}
}
return 0;
}
/*
* peep2(bp) - scan blocks starting at 'bp'
*/
static bool
peep2(bp)
register BLOCK *bp;
{
register INST *ip;
register bool changed = FALSE;
register int pnum;
#ifdef DEBUG
if (debug)
fprintf(stderr, "peep2: ");
#endif
for (; bp != NULL ;bp = bp->next) {
for (ip = bp->first; ip != NULL && ip->next != NULL ;) {
if (pnum = ipeep2(bp, ip)) {
changed = TRUE;
s_peep2++;
#ifdef DEBUG
if (debug)
fprintf(stderr, "%d ", pnum);
#endif
/*
* If we had a match, then either instruction
* may have been deleted, so the safe thing to
* do is to start the block over.
*/
ip = bp->first;
} else
ip = ip->next;
}
}
#ifdef DEBUG
if (debug)
fprintf(stderr, "\n");
#endif
return changed;
}
/*
* ipeep3(bp, ip) - look for 3-instruction optimizations at the given inst.
*/
static int
ipeep3(bp, i1)
register BLOCK *bp;
register INST *i1;
{
INST *i2 = i1->next; /* the next instruction */
INST *i3 = i1->next->next; /* the third instruction */
/*
* move.l Am, Dn => lea N(Am), Ao
* add.l #N, Dn
* move.l Dn, Ao
*
* Also, Dn must be dead after the third instruction.
*/
if ((i1->opcode == MOVE) && (i1->flags & LENL) &&
(i1->src.amode == REG) &&
ISA(i1->src.areg) &&
(i1->dst.amode == REG) &&
ISD(i1->dst.areg)) {
if (((i2->opcode == ADD) || (i2->opcode == ADDQ)) &&
(i2->flags & LENL) &&
(i2->src.amode == IMM) &&
DOK(i2->src.disp) &&
(i2->dst.amode == REG) &&
(i2->dst.areg == i1->dst.areg)) {
if ((i3->opcode == MOVE) && (i3->flags & LENL) &&
(i3->src.amode == REG) &&
(i3->src.areg == i1->dst.areg) &&
(i3->dst.amode == REG) &&
ISA(i3->dst.areg) &&
((i3->live & RM(i3->src.areg)) == 0)) {
/*
* rewrite i1 and delete i2 and i3
*/
i1->opcode = LEA;
i1->flags = 0;
i1->dst = i3->dst;
i1->src.amode = REGID;
i1->src.disp = i2->src.disp;
delinst(bp, i2);
delinst(bp, i3);
s_idel += 2;
return 1;
}
}
}
/*
* move.l Am, Dn => lea 0(Am, Do), Ap
* add.x Do, Dn
* move.l Dn, Ap
*
* The second instruction can be either a word or long add.
* Also, Dn must be dead after the third instruction.
*/
if ((i1->opcode == MOVE) && (i1->flags & LENL) &&
(i1->src.amode == REG) &&
ISA(i1->src.areg) &&
(i1->dst.amode == REG) &&
ISD(i1->dst.areg)) {
if (((i2->opcode == ADD) || (i2->opcode == ADDQ)) &&
(i2->flags & (LENL|LENW)) &&
(i2->src.amode == REG) &&
ISD(i2->src.areg) && (i1->dst.areg != i2->src.areg) &&
(i2->dst.amode == REG) &&
(i2->dst.areg == i1->dst.areg)) {
if ((i3->opcode == MOVE) && (i3->flags & LENL) &&
(i3->src.amode == REG) &&
(i3->src.areg == i1->dst.areg) &&
(i3->dst.amode == REG) &&
ISA(i3->dst.areg) &&
((i3->live & RM(i3->src.areg)) == 0)) {
/*
* rewrite i1 and delete i2 and i3
*/
i1->opcode = LEA;
i1->flags = 0;
i1->dst = i3->dst;
i1->src.amode = REGIDX;
if (i2->flags & LENL)
i1->src.amode |= XLONG;
i1->src.ireg = i2->src.areg;
i1->src.disp = 0;
delinst(bp, i2);
delinst(bp, i3);
s_idel += 2;
return 2;
}
}
}
/*
* move.l X(Am), Dn => move.l X(Am), Ao
* add.l #N, Dn
* move.l Dn, Ao lea N(Ao), Ao
*
* Also, Dn must be dead after the third instruction.
*/
if ((i1->opcode == MOVE) && (i1->flags & LENL) &&
(i1->src.amode == REGI || i1->src.amode == REGID) &&
(i1->dst.amode == REG) &&
ISD(i1->dst.areg)) {
if (((i2->opcode == ADD) || (i2->opcode == ADDQ)) &&
(i2->flags & LENL) &&
(i2->src.amode == IMM) &&
DOK(i2->src.disp) &&
(i2->dst.amode == REG) &&
(i2->dst.areg == i1->dst.areg)) {
if ((i3->opcode == MOVE) && (i3->flags & LENL) &&
(i3->src.amode == REG) &&
(i3->src.areg == i1->dst.areg) &&
(i3->dst.amode == REG) &&
ISA(i3->dst.areg) &&
((i3->live & RM(i3->src.areg)) == 0)) {
/*
* rewrite i1 and i3 and delete i2
*/
i1->dst = i3->dst;
i3->opcode = LEA;
i3->flags = 0;
i3->src.amode = REGID;
i3->src.areg = i3->dst.areg;
i3->src.disp = i2->src.disp;
delinst(bp, i2);
s_idel++;
return 3;
}
}
}
/*
* move.l Am, An
* addq.l #1, Am
* ... stuff ...
* ???.b ..(An).. => ???.b ..(Am)+..
*
* An must be dead after the last instruction. Nothing in
* "stuff" can modify Am.
*/
if ((i1->opcode == MOVE) && (i1->flags & LENL) &&
(i1->src.amode == REG) && ISA(i1->src.areg) &&
(i1->dst.amode == REG) && ISA(i1->dst.areg)) {
int rm = i1->src.areg;
int rn = i1->dst.areg;
if (((i2->opcode == ADD) || (i2->opcode == ADDQ)) &&
(i2->flags & LENL) &&
(i2->src.amode == IMM) && (i2->src.disp == 1) &&
(i2->dst.amode == REG) &&
(i2->dst.areg == rm)) {
while (i3 != NULL) {
if (sets(i3, RM(rm)))
return 0;
if (i3->src.amode==REGI && i3->src.areg==rn) {
if (i3->live & RM(rn))
return 0;
if ((i3->flags & LENB) == 0)
return 0;
i3->src.amode |= INC;
i3->src.areg = rm;
delinst(bp, i1);
delinst(bp, i2);
s_idel += 2;
return 4;
}
if (i3->dst.amode==REGI && i3->dst.areg==rn) {
if (i3->live & RM(rn))
return 0;
if ((i3->flags & LENB) == 0)
return 0;
i3->dst.amode |= INC;
i3->dst.areg = rm;
delinst(bp, i1);
delinst(bp, i2);
s_idel += 2;
return 4;
}
if (i3->next == NULL)
return 0;
else
i3 = i3->next;
}
}
}
/*
* move.l Am, An
* addq.l #2, Am
* ... stuff ...
* ???.w ..(An).. => ???.w ..(Am)+..
*
* An must be dead after the last instruction. Nothing in
* "stuff" can modify Am.
*/
if ((i1->opcode == MOVE) && (i1->flags & LENL) &&
(i1->src.amode == REG) && ISA(i1->src.areg) &&
(i1->dst.amode == REG) && ISA(i1->dst.areg)) {
int rm = i1->src.areg;
int rn = i1->dst.areg;
if (((i2->opcode == ADD) || (i2->opcode == ADDQ)) &&
(i2->flags & LENL) &&
(i2->src.amode == IMM) && (i2->src.disp == 2) &&
(i2->dst.amode == REG) &&
(i2->dst.areg == rm)) {
while (i3 != NULL) {
if (sets(i3, RM(rm)))
return 0;
if (i3->src.amode==REGI && i3->src.areg==rn) {
if (i3->live & RM(rn))
return 0;
if ((i3->flags & LENW) == 0)
return 0;
i3->src.amode |= INC;
i3->src.areg = rm;
delinst(bp, i1);
delinst(bp, i2);
s_idel += 2;
return 5;
}
if (i3->dst.amode==REGI && i3->dst.areg==rn) {
if (i3->live & RM(rn))
return 0;
if ((i3->flags & LENW) == 0)
return 0;
i3->dst.amode |= INC;
i3->dst.areg = rm;
delinst(bp, i1);
delinst(bp, i2);
s_idel += 2;
return 4;
}
if (i3->next == NULL)
return 0;
else
i3 = i3->next;
}
}
}
/*
* move.l Am, An
* addq.l #4, Am
* ... stuff ...
* ???.l ..(An).. => ???.l ..(Am)+..
*
* An must be dead after the last instruction. Nothing in
* "stuff" can modify Am.
*/
if ((i1->opcode == MOVE) && (i1->flags & LENL) &&
(i1->src.amode == REG) && ISA(i1->src.areg) &&
(i1->dst.amode == REG) && ISA(i1->dst.areg)) {
int rm = i1->src.areg;
int rn = i1->dst.areg;
if (((i2->opcode == ADD) || (i2->opcode == ADDQ)) &&
(i2->flags & LENL) &&
(i2->src.amode == IMM) && (i2->src.disp == 4) &&
(i2->dst.amode == REG) &&
(i2->dst.areg == rm)) {
while (i3 != NULL) {
if (sets(i3, RM(rm)))
return 0;
if (i3->src.amode==REGI && i3->src.areg==rn) {
if (i3->live & RM(rn))
return 0;
if ((i3->flags & LENL) == 0)
return 0;
i3->src.amode |= INC;
i3->src.areg = rm;
delinst(bp, i1);
delinst(bp, i2);
s_idel += 2;
return 6;
}
if (i3->dst.amode==REGI && i3->dst.areg==rn) {
if (i3->live & RM(rn))
return 0;
if ((i3->flags & LENL) == 0)
return 0;
i3->dst.amode |= INC;
i3->dst.areg = rm;
delinst(bp, i1);
delinst(bp, i2);
s_idel += 2;
return 4;
}
if (i3->next == NULL)
return 0;
else
i3 = i3->next;
}
}
}
return 0;
}
/*
* peep3(bp) - scan blocks starting at 'bp'
*/
static bool
peep3(bp)
register BLOCK *bp;
{
register INST *ip;
register bool changed = FALSE;
register int pnum;
/*
* All of the 3-inst stuff requires data-flow analysis
*/
if (!do_dflow)
return FALSE;
#ifdef DEBUG
if (debug)
fprintf(stderr, "peep3: ");
#endif
for (; bp != NULL ;bp = bp->next) {
ip = bp->first;
while (ip!=NULL && ip->next != NULL && ip->next->next != NULL) {
if (pnum = ipeep3(bp, ip)) {
changed = TRUE;
s_peep3++;
#ifdef DEBUG
if (debug)
fprintf(stderr, "%d ", pnum);
#endif
/*
* If we had a match, then any instruction
* could have been deleted, so the safe thing
* to do is to start the block over.
*/
ip = bp->first;
} else
ip = ip->next;
}
}
#ifdef DEBUG
if (debug)
fprintf(stderr, "\n");
#endif
return changed;
}
void
peep(bp)
register BLOCK *bp;
{
extern BLOCK *fhead;
bool changed;
peep1(bp);
/*
* Loop until no more changes are made. After each change, do
* live/dead analysis or the data gets old. In each loop, make
* at most one change.
*/
for (changed = TRUE; changed ;rhealth(fhead)) {
if (peep2(bp))
changed = TRUE;
else if (peep3(bp))
changed = TRUE;
else
changed = FALSE;
}
}