/* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews * Patched -- PvO -- see file patch * * * 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. */ /* * 3-instruction peephole optimizations */ #include "top.h" /* * ipeep3(bp, ip) - look for 3-instruction optimizations at the given inst. */ static bool ipeep3(bp, i1) register BLOCK *bp; register INST *i1; { register INST *i2 = i1->next; /* the next instruction */ INST *i3 = i1->next->next; /* the third instruction */ register int op1 = i1->opcode; register int op2 = i2->opcode; register int op3 = i3->opcode; /* * 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 ((op1 == MOVE) && (i1->flags & LENL) && (i1->src.amode == REG) && ISA(i1->src.areg) && (i1->dst.amode == REG) && ISD(i1->dst.areg)) { if (((op2 == ADD) || (op2 == ADDQ)) && (i2->flags & LENL) && (i2->src.amode == IMM) && DOK(i2->src.disp) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg)) { if ((op3 == 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); DBG(printf("%d ", __LINE__)) return TRUE; } } } /* * move.l Dm, Dn => move.l Dm, Ao * add.l #N, Dn lea N(Ao), Ao * move.l Dn, Ao * * Also, Dn must be dead after the third instruction. */ if ((op1 == MOVE) && (i1->flags & LENL) && (i1->src.amode == REG) && ISD(i1->src.areg) && (i1->dst.amode == REG) && ISD(i1->dst.areg)) { if (((op2 == ADD) || (op2 == ADDQ)) && (i2->flags & LENL) && (i2->src.amode == IMM) && DOK(i2->src.disp) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg)) { if ((op3 == 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 i2 and delete i3 */ i1->dst.areg = i3->dst.areg; i2->opcode = LEA; i2->flags = 0; i2->dst = i3->dst; i2->src.amode = REGID; i2->src.areg = i2->dst.areg; i2->src.disp = i2->src.disp; delinst(bp, i3); DBG(printf("%d ", __LINE__)) return TRUE; } } } /* * move.l Am, Dn => lea -N(Am), Ao * sub.l #N, Dn * move.l Dn, Ao * * Also, Dn must be dead after the third instruction. */ if ((op1 == MOVE) && (i1->flags & LENL) && (i1->src.amode == REG) && ISA(i1->src.areg) && (i1->dst.amode == REG) && ISD(i1->dst.areg)) { if (((op2 == SUB) || (op2 == ADDQ)) && (i2->flags & LENL) && (i2->src.amode == IMM) && DOK(i2->src.disp) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg)) { if ((op3 == 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); DBG(printf("%d ", __LINE__)) return TRUE; } } } /* * 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 ((op1 == MOVE) && (i1->flags & LENL) && (i1->src.amode == REG) && ISA(i1->src.areg) && (i1->dst.amode == REG) && ISD(i1->dst.areg)) { if (((op2 == ADD) || (op2 == 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 ((op3 == 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); DBG(printf("%d ", __LINE__)) return TRUE; } } } /* * 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 ((op1 == MOVE) && (i1->flags & LENL) && (i1->src.amode == REGI || i1->src.amode == REGID) && (i1->dst.amode == REG) && ISD(i1->dst.areg)) { if (((op2 == ADD) || (op2 == ADDQ)) && (i2->flags & LENL) && (i2->src.amode == IMM) && DOK(i2->src.disp) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg)) { if ((op3 == 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); DBG(printf("%d ", __LINE__)) return TRUE; } } } /* * move.x X, Dn => move.x X, Do * ext.y Dn ext.y Do * move.y Dn, Do * * Where Dn is dead. */ if ((op1 == MOVE)&&(op2 == EXT)&&(op3 == MOVE)&& (i1->dst.amode == REG) && ISD(i1->dst.areg) && (i2->src.amode == REG) && (i3->src.amode == REG) && (i3->dst.amode == REG) && ISD(i3->dst.areg) && (i1->dst.areg == i2->src.areg) && (i1->dst.areg == i3->src.areg) && (i2->flags == i3->flags)) { if ((i3->live & RM(i3->src.areg)) == 0) { i1->dst.areg = i3->dst.areg; i2->src.areg = i3->dst.areg; delinst(bp, i3); DBG(printf("%d ", __LINE__)) return TRUE; } } /* * move.l X, Dm => move.l X, An * INST INST * move.l Dm, An ...deleted... * * where INST doesn't modify Dm, and Dm is dead after i3 */ if ((op1 == MOVE) && (op3 == MOVE) && (i1->dst.amode == REG) && ISD(i1->dst.areg) && (i3->src.amode == REG) && (i1->dst.areg == i3->src.areg) && (i3->dst.amode == REG) && ISA(i3->dst.areg) && !uses(i2, i3->src.areg) && !uses(i2, i3->dst.areg)) { if ((i3->live & RM(i3->src.areg)) == 0) { i1->dst.areg = i3->dst.areg; delinst(bp, i3); DBG(printf("%d ", __LINE__)) return TRUE; } } /* * move.l Am, An ...deleted... * addq.l #1, Am ...deleted... * ... stuff ... ... stuff ... * ???.b ..(An).. => ???.b ..(Am)+.. * * An must be dead after the last instruction. Nothing in * "stuff" can modify Am. */ if ((op1 == 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 (((op2 == ADD) || (op2 == 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)) goto end7; if (i3->src.amode==REGI && i3->src.areg==rn) { if (i3->live & RM(rn)) goto end7; if ((i3->flags & LENB) == 0) goto end7; i3->src.amode |= INC; i3->src.areg = rm; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } if (i3->dst.amode==REGI && i3->dst.areg==rn) { if (i3->live & RM(rn)) goto end7; if ((i3->flags & LENB) == 0) goto end7; i3->dst.amode |= INC; i3->dst.areg = rm; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } if (i3->next == NULL) goto end7; else i3 = i3->next; } } } end7: /* * 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 ((op1 == 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 (((op2 == ADD) || (op2 == 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)) goto end9; if (i3->src.amode==REGI && i3->src.areg==rn) { if (i3->live & RM(rn)) goto end9; if ((i3->flags & LENW) == 0) goto end9; i3->src.amode |= INC; i3->src.areg = rm; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } if (i3->dst.amode==REGI && i3->dst.areg==rn) { if (i3->live & RM(rn)) goto end9; if ((i3->flags & LENW) == 0) goto end9; i3->dst.amode |= INC; i3->dst.areg = rm; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } if (i3->next == NULL) goto end9; else i3 = i3->next; } } } end9: /* * 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 ((op1 == 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 (((op2 == ADD) || (op2 == 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)) goto end11; if (i3->src.amode==REGI && i3->src.areg==rn) { if (i3->live & RM(rn)) goto end11; if ((i3->flags & LENL) == 0) goto end11; i3->src.amode |= INC; i3->src.areg = rm; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } if (i3->dst.amode==REGI && i3->dst.areg==rn) { if (i3->live & RM(rn)) goto end11; if ((i3->flags & LENL) == 0) goto end11; i3->dst.amode |= INC; i3->dst.areg = rm; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } if (i3->next == NULL) goto end11; else i3 = i3->next; } } } end11: return FALSE; } /* * peep3(bp) - scan blocks starting at 'bp' */ bool peep3(bp) register BLOCK *bp; { register INST *ip; register bool changed = FALSE; DBG(printf("p3: ")) for (; bp != NULL ;bp = bp->next) { ip = bp->first; while (ip!=NULL && ip->next != NULL && ip->next->next != NULL) { if (ipeep3(bp, ip)) { s_peep3++; bprep(bp); changed = TRUE; /* * If we had a match, then any instruction * could have been deleted, so the safe thing * to do is to go to the next block. */ break; } else ip = ip->next; } } DBG(printf("\n"); fflush(stdout)) return changed; }