Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sun-barr!ccut!wnoc-tyo-news!sragwa!sranha!srava!nisimura From: nisimura@srava.sra.co.jp (Tohru Nisimura) Newsgroups: comp.sys.atari.st.tech Subject: (unofficial) Patches for Sozobon TOP v1.2 (2/2) Message-ID: <4732@srava.sra.co.jp> Date: 31 Oct 90 01:30:21 GMT Reply-To: nisimura@sra.co.JP (Tohru Nisimura) Organization: Software Research Associates, Inc., Japan Lines: 1393 This is source & context-diff part of Sozobon TOP v1.2x. Bug report/fix are welcome. I have never modified other part of TOP codes. I'm sure there is more room to be hacked. (It seems that the original author, Tony Andrews, has an intend to apply register colouring scheme). Tohru Nishimura Software Research Associates, Tokyo, Japan INTERNET: nisimura@sra.co.jp -------------- >8 -------- zip zip ----------- 8< --------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # change1.2x # peep1.c # peep2.c # peep3.c # health.dif # main.dif # This archive created: Wed Oct 31 10:01:53 JST 1990 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'change1.2x' then echo shar: "will not over-write existing file 'change1.2x'" else cat << \SHAR_EOF > 'change1.2x' ============================================================ Sozobon Optimizer v1.2x Change Notes -- Oct 1, 1990 by Tohru NISHIMURA, SRA Inc., Tokyo ============================================================ This notes describes modifications about Sozobon Optimizer "top" v1.2x. o General Peep hole optimization is modified extensively. a. chances to optimize were extended. b. cases which seldom happen were deleted. c. orders of case analysis were changed for fast decisions. d. case analysis bugs were fixed. e. "address register indirect with index" addressing mode is used as much as possible. o Problems & Fixes 1. top v1.20 sometimes does his work under unnecessary conditions. => Just a case analysis error: fixed. 2. Sozobon Compiler, "hcc", is too innocent about effective address calculation scheme, especially for an element of structure array. Array reference is done as follows; a. calculate index b. extend the value to long (with/without sign-extent) c. add base address d. move the result to one address register e. make a reference using either register indirect mode or register indirect with displacement mode. This procedure is simplified with a MC68000 versatile addressing mode; "address register indirect with index" mode. With this mode, a reference to an element of struct array is done intuitionally. top v1.2x uses the addressing mode as much as possible. In best case, the optimizing effort saves 2 words space and a few clocks for each instance. In worst case, it results in just an exchange of operands between two instructions. 3. top v1.20 sometimes fails to optimize in spite of that it is coded to do. => Some are due to case analysis error, others due to Sozobon C convention. Former was fixed, latter not. Description of latter problem: d0 register is used for returning function result. top v1.20 blindly assumes that rts/rtd/rte instructions refer to sp and d0, even if the function type is void. This infers top's optimizing procedure. If a function actually returns a value, there is no problem. Because value assignment to d0 register is always preceding to rts/rtd/rte (that is, d0 becomes "dead" near at the end of function), thus intermediate d0 can be subject to optimize for top. If the function returns no value, top would think d0 register is being alive until the end of function. In this case, every d0-relating optimization instances just preceding to rts/rtd/rte will fail to work. To solve this problem completely, hcc must be modified. o Open problems 1. hcc should use "address register indirect with index" mode for oneself. The efforts of top v1.2x will not work well in some cases. 2. hcc does not utilize contents of registers at all. Effective addresses are calculated on every instances, even if the same value is alive in registers. This approach simplifies hcc, but the elimination of common expressions should be done in compiler, rather than optimizer. 3. code reduction with bit instruction; some code sequences can be optimized using bit instructions, btst, bset. For example, if ((x & (1 << y)) == 0) ... x |= (1 << y); bit instructions cannot be used via C language directly, this kind of optimization may be actually what optimizers should do. 4. register a2 and d2 are never used for any purpose. They may be reserved for scratch registers, but I have never seen hcc used them. top does not utilize them for "registerising". --- end of change --- SHAR_EOF fi if test -f 'peep1.c' then echo shar: "will not over-write existing file 'peep1.c'" else cat << \SHAR_EOF > 'peep1.c' /* 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. * * Modified by Tohru Nishimura, Software Research Associates, Tokyo, Oct 1990. */ /* * Single-instruction peephole optimizations and the overall driver routine. */ #include "top.h" void peep(bp) register BLOCK *bp; { bool peep1(), peep2(), peep3(); extern BLOCK *fhead; register 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. */ do { changed = peep3(bp); if (!changed) changed = peep2(bp); if (!changed) changed = peep1(bp); rhealth(fhead, FALSE); } while (changed); } /* * ipeep1(ip) - check for changes to the instruction 'ip' */ static bool ipeep1(bp, ip) register BLOCK *bp; register INST *ip; { /* * clr.l Dn => moveq.l #0, Dn */ if ((ip->opcode == CLR) && (ip->flags & LENL) && (ip->src.amode == REG) && ISD(ip->src.areg)) { ip->opcode = MOVEQ; ip->dst = ip->src; /* we'll have two operands now */ ip->src.amode = IMM; ip->src.disp = 0L; DBG(printf("%d ", __LINE__)) return TRUE; } /* * move.x #n,Dn => moveq.l #n, Dn * * moveq is always a long operation, but as long as the immediate * value is appropriate, we don't care what the original length * was. Clearing upper bytes won't matter. */ if ((ip->opcode == MOVE) && (ip->src.amode == IMM) && D8OK(ip->src.disp) && (ip->dst.amode == REG) && ISD(ip->dst.areg)) { ip->opcode = MOVEQ; ip->flags = LENL; DBG(printf("%d ", __LINE__)) return TRUE; } /* * add.x #n, X => addq.x #n, X * * where 1 <= n <= 8 */ if ((ip->opcode == ADD) && (ip->src.amode == IMM) && (ip->src.disp <= 8L) && (ip->src.disp >= 1L)) { ip->opcode = ADDQ; DBG(printf("%d ", __LINE__)) return TRUE; } /* * sub.x #n, X => subq.x #n, X * * where 1 <= n <= 8 */ if ((ip->opcode == SUB) && (ip->src.amode == IMM) && (ip->src.disp <= 8L) && (ip->src.disp >= 1L)) { ip->opcode = SUBQ; DBG(printf("%d ", __LINE__)) return TRUE; } /* * 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; DBG(printf("%d ", __LINE__)) return TRUE; } /* * movem.x (sp)+, Reg => move.x (sp)+, Reg */ if ((ip->opcode == MOVEM) && (ip->dst.amode == REG) && (ip->src.areg == SP) && (ip->src.amode == (REGI|INC))) { ip->opcode = MOVE; DBG(printf("%d ", __LINE__)) return TRUE; } /* * add[q] #?, Rn * * Remove instruction if Rn is dead. This is most often used * to eliminate the fixup of SP following a function call when * we're just about to return, since the "unlk" clobbers SP * anyway. */ if ((ip->opcode == ADDQ || (ip->opcode == ADD && ip->src.amode == IMM)) && (ip->dst.amode == REG)) { if ((ip->live & RM(ip->dst.areg)) == 0) { delinst(bp, ip); DBG(printf("%d ", __LINE__)) return TRUE; } } /* * move.x X, X * * Delete as long as X isn't INC or DEC */ if ((ip->opcode == MOVE) && opeq(&ip->src, &ip->dst) && ((ip->src.amode & (INC|DEC)) == 0)) { delinst(bp, ip); DBG(printf("%d ", __LINE__)) return TRUE; } /* * move.x Rm, Rn * * Delete if Rn is dead. */ if ((ip->opcode == MOVE) && (ip->src.amode == REG) && (ip->dst.amode == REG)) { if ((ip->live & RM(ip->dst.areg)) == 0) { delinst(bp, ip); DBG(printf("%d ", __LINE__)) return TRUE; } } /* * cmp.x #0, X => tst.x X * beq/bne beq/bne * * Where X is not An */ if ((bp->last == ip) && (bp->bcode == BEQ || bp->bcode == BNE) && (ip->opcode == CMP) && (ip->src.amode == IMM) && (ip->src.disp == 0L) && (ip->dst.amode != REG || ISD(ip->dst.areg))) { ip->opcode = TST; ip->src = ip->dst; ip->dst.amode = NONE; DBG(printf("%d ", __LINE__)) return TRUE; } /* * add.x #n, Am => lea n(Am), Am * * Where 'n' is a valid [-32768..32767] displacement */ if ((ip->opcode == ADD) && (ip->src.amode == IMM) && DOK(ip->src.disp) && (ip->dst.amode == REG) && ISA(ip->dst.areg)) { ip->opcode = LEA; ip->src.amode = REGID; ip->src.areg = ip->dst.areg; ip->flags = 0; DBG(printf("%d ", __LINE__)) return TRUE; } /* * lea 0(Am,Rn.?), Am => add.? Rn, Am * * This is the result of 2nd stage */ if ((ip->opcode == LEA) && (ip->src.amode == REGIDX || ip->src.amode == (REGIDX|XLONG)) && (ip->src.disp == 0L) && (ip->src.areg == ip->dst.areg)) { ip->opcode = ADD; ip->flags = (ip->src.amode & XLONG) ? LENL : LENW; ip->src.amode = REG; ip->src.areg = ip->src.ireg; DBG(printf("%d ", __LINE__)) return TRUE; } return FALSE; } /* * peep1(bp) - peephole optimizations with a window size of 1 */ static bool peep1(bp) register BLOCK *bp; { register INST *ip; register bool changed = FALSE; register bool bchange; DBG(printf("p1: ")) for (; bp != NULL ;bp = bp->next) { bchange = FALSE; for (ip = bp->first; ip != NULL ;ip = ip->next) { if (ipeep1(bp, ip)) { s_peep1++; changed = TRUE; bchange = TRUE; } } if (bchange) bprep(bp); } DBG(printf("\n"); fflush(stdout)) return changed; } SHAR_EOF fi if test -f 'peep2.c' then echo shar: "will not over-write existing file 'peep2.c'" else cat << \SHAR_EOF > 'peep2.c' /* 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. * * Modified by Tohru Nishimura, Software Research Associates, Tokyo, Oct 1990. */ /* * 2-instruction peephole optimizations */ #include "top.h" /* * ipeep2(bp, i1) - look for 2-instruction optimizations at the given inst. */ static bool ipeep2(bp, i1) BLOCK *bp; register INST *i1; { register INST *i2; /* the next instruction */ register int op1, op2; /* opcodes, for speed */ i2 = i1->next; op1 = i1->opcode; op2 = i2->opcode; /* * Avoid stack fix-ups after a call if possible. */ /* * add[q].l #N, sp ...deleted... * ... stuff ... ... stuff ... * move.x ?, -(sp) => move.x ?, (sp) * * where N is * 2, then x should be w * 4, then x should be l * Nothing in "stuff" can use SP. */ if ((op1 == ADDQ || (op1 == ADD && i1->src.amode == IMM)) && (i1->src.disp == 2L || i1->src.disp == 4L) && (i1->dst.areg == SP) && (i1->dst.amode == REG)) { register INST *ti2 = i2; int len = i1->src.disp & (LENW|LENL); while (!uses(ti2, SP)) { if (ti2->next == NULL) goto end1; ti2 = ti2->next; } if ((ti2->opcode == MOVE) && (ti2->flags & len) && (ti2->dst.areg == SP) && (ti2->dst.amode == (REGI|DEC))) { ti2->dst.amode = REGI; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } } end1: /* * Avoid "tst" instructions following instructions that * set the Z flag. */ /* * move.x X, Y => move.x X, Y * tst.x X or Y ...deleted... * beq/bne beq/bne * * where Y is not An, because "movea" doesn't set the * zero flag. * Also "tst" is must not be DEC nor INC. */ if ((bp->last == i2) && (bp->bcode == BEQ || bp->bcode == BNE) && (op1 == MOVE) && (op2 == TST) && (i1->flags == i2->flags) && (i1->dst.amode != REG || ISD(i1->dst.areg)) && (opeq(&i1->src, &i2->src) || opeq(&i1->dst, &i2->src)) && (i2->src.amode & (DEC|INC)) == 0) { delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * and.x X, Y => and.x X, Y * tst.x Y ...deleted... * beq/bne beq/bne * */ if ((bp->last == i2) && (bp->bcode == BEQ || bp->bcode == BNE) && (op1 == AND) && (op2 == TST) && (i1->flags == i2->flags) && opeq(&i1->dst, &i2->src)) { delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * ext.x Dn => ext.x Dn * tst.x Dn ...deleted... * beq/bne beq/bne * * "ext" implies that its operand is data register direct. */ if ((bp->last == i2) && (bp->bcode == BEQ || bp->bcode == BNE) && (op1 == EXT) && (op2 == TST) && (i1->flags == i2->flags) && (i1->src.areg == i2->src.areg)) { delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * move.x X, Dn => move.x X, Dn * ext.y Dn ...deleted... * beq/bne beq/bne * * where Dn is dead after the "ext". */ if ((bp->last == i2) && (bp->bcode == BEQ || bp->bcode == BNE) && (op1 == MOVE) && (op2 == EXT) && (i1->dst.areg == i2->src.areg) && (i2->live & RM(i2->src.areg)) == 0) { delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * ext.l Dm => ...deleted... * tst.l Dm tst.w Dm * * where Dm is dead after the "tst". */ if ((op1 == EXT) && (op2 == TST) && ((i1->flags & i2->flags) & LENL) && (i2->src.areg == i1->src.areg) && (i2->live & RM(i2->src.areg)) == 0) { i2->flags = LENW; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } /* * Avoid intermediate registers. */ /* * move.x X, Dm => INST.x X, Dn * INST.x Dm, Dn ....deleted.... * * where Dm is dead, and INST is one of: add, sub, and, or, cmp */ if ((op1 == MOVE) && ((op2==ADD)||(op2==SUB)||(op2==AND)||(op2==OR)||(op2==CMP)) && (i1->flags == i2->flags) && (i1->dst.amode == REG) && ISD(i1->dst.areg) && (i2->src.areg == i1->dst.areg) && (i2->dst.amode == REG) && ISD(i2->dst.areg) && (i2->live & RM(i2->src.areg)) == 0) { i1->opcode = i2->opcode; i1->dst.areg = i2->dst.areg; delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * Silly moves */ /* * move.x X, Y => move.x X, Y * move.x Y, X ...deleted... */ if ((op1 == MOVE) && (op2 == MOVE) && (i1->flags == i2->flags) && opeq(&i1->src, &i2->dst) && opeq(&i1->dst, &i2->src) && ((i1->src.amode & i1->dst.amode) & (INC|DEC)) == 0) { delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * move.x X, Y => move.x X, Rn * move.x Y, Rn move.x Rn, Y * * where Y isn't INC or DEC, and not register direct */ if ((op1 == MOVE) && (op2 == MOVE) && (i1->flags == i2->flags) && (i1->dst.amode != REG) && ((i1->dst.amode & (INC|DEC)) == 0) && (i2->dst.amode == REG) && opeq(&i1->dst, &i2->src)) { i1->dst = i2->dst; i2->dst = i2->src; i2->src = i1->dst; DBG(printf("%d ", __LINE__)) return TRUE; } /* * move.x Rn, X => move.x Rn, X * move.x X, Y move.x Rn, Y * * where X isn't INC or DEC, and not register direct */ if ((op1 == MOVE) && (op2 == MOVE) && (i1->flags == i2->flags) && (i1->src.amode == REG) && (i1->dst.amode != REG) && ((i1->dst.amode & (DEC|INC)) == 0) && opeq(&i1->dst, &i2->src)) { i2->src = i1->src; DBG(printf("%d ", __LINE__)) return TRUE; } /* * move.x Rm, Rn => move.x Rm, Rn * ... stuff ... ... stuff ... * move.x Rm, Rn * * where "stuff" doesn't set Rm nor Rn. Also make sure that * the second move isn't followed by a conditional branch. * In that case leave everything alone since the branch * probably relies on flags set by the move. */ if ((op1 == MOVE) && (i1->src.amode == REG) && (i1->dst.amode == REG)) { register INST *ti2 = i2; register int sreg = i1->src.areg; register int dreg = i1->dst.areg; while (!sets(ti2, dreg)) { if (sets(ti2, sreg) || ti2->next == NULL) goto end2; ti2 = ti2->next; } if ((ti2->opcode == MOVE) && (ti2->flags == i1->flags) && (ti2->src.amode == REG) && (ti2->src.areg == sreg) && (bp->last != ti2 || bp->bcond == NULL)) { delinst(bp, ti2); DBG(printf("%d ", __LINE__)) return TRUE; } } end2: /* * move.x Dm, X => move.x Dm, X * cmp.x #N, X cmp.x #N, Dm * * where X isn't INC or DEC, and not register direct. * * Since X generally references memory, we can compare * with the register faster. */ if ((op1 == MOVE) && (op2 == CMP) && (i1->flags == i2->flags) && (i1->src.amode == REG) && ISD(i1->src.areg) && (i1->dst.amode != REG) && ((i1->dst.amode & (INC|DEC)) == 0) && (i2->src.amode == IMM) && opeq(&i2->dst, &i1->dst)) { i2->dst.amode = REG; i2->dst.areg = i1->src.areg; DBG(printf("%d ", __LINE__)) return TRUE; } /* * INST X, An => INST X, Ao * lea (An), Ao * * where An is dead after the second instruction. */ if ((op2 == LEA) && (i1->dst.amode == REG) && ISA(i1->dst.areg) && (i2->src.amode == REGI) && (i2->src.areg == i1->dst.areg) && (i2->live & RM(i2->src.areg)) == 0) { i1->dst.areg = i2->dst.areg; delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * lea X, An => ....deleted.... * INST (An) [, ..] INST X [, ..] * * where An is either dead after the second instruction or * is a direct destination of the second instruction. * or, * lea X, An => ....deleted.... * INST Y, (An) INST Y, X * * where Y doesn't refer to An, and An is dead after the * second instruction. */ if (op1 == LEA) { if ((i2->src.amode == REGI) && (i2->src.areg == i1->dst.areg) && ((i2->live & RM(i1->dst.areg)) == 0 || (i2->dst.amode == REG && i2->dst.areg == i1->dst.areg))) { i2->src = i1->src; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } if ((i2->dst.amode == REGI) && (i2->dst.areg == i1->dst.areg) && ((i2->live & RM(i1->dst.areg)) == 0)) { int i2src = chkref(&i2->src, TRUE); if (i2src == 0 || (i2src & RM(i1->dst.areg)) == 0) { i2->dst = i1->src; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } } } /* * lea N(Am), An => lea N(Am,Ro.l), An * add.l Ro, An ....deleted.... * */ if ((op1 == LEA) && (op2 == ADD) && (i1->src.amode == REGID) && D8OK(i1->src.disp) && (i2->src.amode == REG) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg)) { i1->src.amode = REGIDX | XLONG; i1->src.ireg = i2->src.areg; delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } /* * An array element reference is done by; * 1. calculate its index value * 2. make the result be sign-extented long * 3. sum it with base address * 4. access the target via the result with REGI or REGID mode * In most cases, procedure 2,3,4 are reduced to * a single REGIDX.w mode access. */ /* * add.l Am, Rn => ....deleted.... * move.l Rn, Ao lea 0(Am,Rn.l), Ao * * add.l X, Rn => move.l X, Ao * move.l Rn, Ao lea 0(Ao,Rn.l), Ao * * where Rn is dead after the second instruction. * X is not address register direct, predec, postinc. */ if ((op1 == ADD) && (op2 == MOVE) && ((i1->flags & i2->flags) & LENL) && (i1->dst.amode == REG) && (i2->src.amode == REG) && (i2->src.areg == i1->dst.areg) && (i2->dst.amode == REG) && ISA(i2->dst.areg) && (i2->live & RM(i2->src.areg)) == 0) { if ((i1->src.amode == REG) && ISA(i1->src.areg)) { i2->opcode = LEA; i2->src.amode = REGIDX | XLONG; i2->src.areg = i1->src.areg; i2->src.ireg = i1->dst.areg; i2->src.disp = 0L; i2->flags = 0; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } else if ((i1->src.amode & (DEC|INC)) == 0) { i2->opcode = LEA; i2->src.amode = REGIDX | XLONG; i2->src.areg = i2->dst.areg; i2->src.ireg = i1->dst.areg; i2->src.disp = 0L; i2->flags = 0; i1->opcode = MOVE; i1->dst.areg = i2->dst.areg; DBG(printf("%d ", __LINE__)) return TRUE; } } /* * lea 0(Am,Rn.?), An => ....deleted.... * INST N(An) [, ..] INST N(Am,Rn.?) [, ..] * * where An is either dead after the second instruction or * is a direct destination of the second instruction. * or, * lea 0(Am,Rn.?), An => ....deleted.... * INST X, N(An) INST X, N(Am,Rn.?) * * where X doesn't refer to An, and An is dead after the * second instruction. * N(An) is REGID mode with [-128..127] displacement. */ if ((op1 == LEA) && (i1->src.amode == REGIDX || i1->src.amode == (REGIDX|XLONG)) && (i1->src.disp == 0L)) { int reg = i1->dst.areg; if ((i2->src.amode == REGID) && D8OK(i2->src.disp) && (i2->src.areg == reg) && ((i2->live & RM(reg)) == 0 || (i2->dst.amode == REG && i2->dst.areg == reg))) { i1->src.disp = i2->src.disp; i2->src = i1->src; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } if ((i2->dst.amode == REGID) && D8OK(i2->dst.disp) && (i2->dst.areg == reg) && ((i2->live & RM(reg)) == 0)) { int i2src = chkref(&i2->src, TRUE); if (i2src == 0 || (reg & RM(i1->dst.areg)) == 0) { i1->src.disp = i2->dst.disp; i2->dst = i1->src; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } } } end4: /* * ext.l Dn => ...deleted... * ... stuff ... ... stuff ... * INST N(Am,Dn.l) [, ..] INST N(Am,Dn.w) [, ..] * * where An is either dead after the second instruction or * is a direct destination of the second instruction. */ if ((op1 == EXT) && (i1->flags & LENL)) { register INST *ti2 = i2; register int reg = i1->src.areg; while (!uses(ti2, reg)) { if (ti2->next == NULL) goto end3; ti2 = ti2->next; } if ((ti2->src.amode == (REGIDX|XLONG)) && ((ti2->live & RM(reg)) == 0 || (ti2->dst.amode == REG && ti2->dst.areg == reg))) { ti2->src.amode &= ~XLONG; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } } end3: /* * Try to use the pre-decrement modes * whenever possible. * * sub.l #N, Am ...deleted... * ... stuff ... ... stuff ... * ???.x ..(Am).. => ???.x ..-(Am).. * * Where N is * 1, then x should be b * 2, then x should be w * 4, then x should be l * Nothing in "stuff" can use Am. */ if ((op1 == SUBQ || (op1 == SUB && i1->src.amode == IMM)) && (i1->flags & LENL) && (i1->src.disp == 1L || i1->src.disp == 2L || i2->src.disp == 4L) && (i1->dst.amode == REG) && ISA(i1->dst.areg)) { register INST *ti2 = i2; register int reg = i1->dst.areg; int len = i1->src.disp & (LENB|LENW|LENL); do { if ((ti2->src.amode == REGI) && (ti2->src.areg == reg)) { if ((ti2->flags & len) == 0) break; ti2->src.amode |= DEC; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } if ((ti2->dst.amode == REGI) && (ti2->dst.areg == reg)) { if ((ti2->flags & len) == 0) break; ti2->dst.amode |= DEC; delinst(bp, i1); DBG(printf("%d ", __LINE__)) return TRUE; } if (uses(ti2, reg)) break; } while ((ti2 = ti2->next) != NULL); } return FALSE; } /* * peep2(bp) - scan blocks starting at 'bp' */ bool peep2(bp) register BLOCK *bp; { register INST *ip; register bool changed = FALSE; DBG(printf("p2: ")) while (bp != NULL) { ip = bp->first; while (ip != NULL && ip->next != NULL) { if (ipeep2(bp, ip)) { changed = TRUE; s_peep2++; bprep(bp); /* * If we had a match, then either instruction * may have been deleted, so the safe thing to * do is to go to the next block. */ break; } ip = ip->next; } bp = bp->next; } DBG(printf("\n"); fflush(stdout)) return changed; } SHAR_EOF fi if test -f 'peep3.c' then echo shar: "will not over-write existing file 'peep3.c'" else cat << \SHAR_EOF > 'peep3.c' /* 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. * * Modified by Tohru Nishimura, Software Research Associates, Tokyo, Oct 1990. */ /* * 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 => ...deleted... * add.l #N, Dn ...deleted... * move.l Dn, Ao lea N(Am), Ao * or, * move.l X, Dn => move.l X, Ao * add.l #N, Dn ...deleted... * move.l Dn, Ao lea N(Ao), Ao * * Also, Dn must be dead after the third instruction. * Where, X is not address register direct. */ if ((op1 == MOVE) && ((op2 == ADD && i2->src.amode == IMM && DOK(i2->src.disp)) || (op2 == ADDQ)) && (op3 == MOVE) && ((i1->flags & i2->flags & i3->flags) & LENL) && (i1->dst.amode == REG) && ISD(i1->dst.areg) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg) && (i3->src.amode == REG) && (i3->src.areg == i1->dst.areg) && (i3->dst.amode == REG) && ISA(i3->dst.areg) ) { DBG(putchar('.')) if ( ((i3->live & RM(i3->src.areg)) == 0)) { if ((i1->src.amode == REG) && ISA(i1->src.areg)) { i3->opcode = LEA; i3->src.amode = REGID; i3->src.areg = i1->src.areg; i3->src.disp = i2->src.disp; i3->flags = 0; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } else { i3->opcode = LEA; i3->src.amode = REGID; i3->src.areg = i3->dst.areg; i3->src.disp = i2->src.disp; i3->flags = 0; i1->dst.areg = i3->dst.areg; delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } }} /* * move.l Am, Dn => ...deleted... * add.l Xn, Dn ...deleted... * move.l Dn, Ap lea 0(Am,Xn.l), Ap * or, * move.l Y, Dn => move.l Y, Ap * add.l Xn, Dn ...deleted... * move.l Dn, Ap lea 0(Ap,Xn.l), Ap * * Also, Dn must be dead after the third instruction. * Y is not address register direct, preinc, postdec. */ if ((op1 == MOVE) && (op2 == ADD) && (op3 == MOVE) && ((i1->flags & i2->flags & i3->flags) & LENL) && (i1->dst.amode == REG) && ISD(i1->dst.areg) && (i2->src.amode == REG) && (i2->src.areg != i1->dst.areg) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg) && (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)) { if ((i1->src.amode == REG) && ISA(i1->src.areg)) { i3->opcode = LEA; i3->src.amode = REGIDX | XLONG; i3->src.areg = i1->src.areg; i3->src.ireg = i2->src.areg; i3->src.disp = 0L; i3->flags = 0; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } else if ((i1->src.amode & (DEC|INC)) == 0) { i3->opcode = LEA; i3->src.amode = REGIDX | XLONG; i3->src.areg = i3->dst.areg; i3->src.ireg = i2->src.areg; i3->src.disp = 0L; i3->flags = 0; i1->dst.areg = i3->dst.areg; delinst(bp, i2); 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) && (op2 == SUB || op2 == SUBQ) && (op3 == MOVE) && ((i1->flags & i2->flags & i3->flags) & LENL) && (i1->src.amode == REG) && ISA(i1->src.areg) && (i1->dst.amode == REG) && ISD(i1->dst.areg) && (i2->src.amode == IMM) && DOK(i2->src.disp) && (i2->dst.amode == REG) && (i2->dst.areg == i1->dst.areg) && (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.areg = i3->dst.areg; i1->src.amode = REGID; i1->src.disp = -i2->src.disp; delinst(bp, i2); delinst(bp, i3); 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) && (i2->src.areg == i1->dst.areg) && (i3->flags == i2->flags) && (i3->src.amode == REG) && (i3->src.areg == i1->dst.areg) && (i3->dst.amode == REG) && ISD(i3->dst.areg)) { 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 use Dm, and Dm is dead after i3. * Further, X should not be An (for safe). */ if ((op1 == MOVE) && (op3 == MOVE) && ((i1->flags & i3->flags) & LENL) && (i1->dst.amode == REG) && ISD(i1->dst.areg) && (i3->src.amode == REG) && (i3->src.areg == i1->dst.areg) && (i3->dst.amode == REG) && ISA(i3->dst.areg) && (i3->dst.areg != i1->src.areg) && !uses(i2, i1->dst.areg) && (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... * add.l #N, Am ...deleted... * ... stuff ... ... stuff ... * ???.x ..(An).. => ???.x ..(Am)+.. * * Where, #N is * 1, then x must be b * 2, then x must be w * 4, then x must be l * Nothing in "stuff" can use Am, nor An. * An must be dead after the last instruction. */ if ((op1 == MOVE) && (op2 == ADD || op2 == ADDQ) && ((i1->flags & i2->flags) & LENL) && (i1->src.amode == REG) && ISA(i1->src.areg) && (i1->dst.amode == REG) && ISA(i1->dst.areg) && (i2->src.amode == IMM) && (i2->src.disp == 1L || i2->src.disp == 2L || i2->src.disp == 4L) && (i2->dst.amode == REG) && (i2->dst.areg == i1->src.areg)) { int rm = i1->src.areg; int rn = i1->dst.areg; int len = i2->src.disp & (LENB|LENW|LENL); do { if (uses(i3, rm)) break; if (i3->src.amode == REGI && i3->src.areg == rn) { if ((i3->flags & len) == 0) goto end7; if (i3->live & RM(rn)) 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->flags & len) == 0) goto end7; if (i3->live & RM(rn)) goto end7; i3->dst.amode |= INC; i3->dst.areg = rm; delinst(bp, i1); delinst(bp, i2); DBG(printf("%d ", __LINE__)) return TRUE; } if (uses(i3, rn)) break; } while ((i3 = i3->next) != NULL); } end7: 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; } ip = ip->next; } } DBG(printf("\n"); fflush(stdout)) return changed; } SHAR_EOF fi if test -f 'health.dif' then echo shar: "will not over-write existing file 'health.dif'" else cat << \SHAR_EOF > 'health.dif' *** top1.2/health.c Fri Aug 24 17:07:04 1990 --- health.c Tue Oct 2 10:15:06 1990 *************** *** 7,12 **** --- 7,14 ---- * 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. + * + * Modified by Tohru Nishimura, Software Research Associates, Tokyo, Oct 1990. */ /* *************** *** 160,172 **** */ for (ip = bp->last; ip != NULL ;ip = ip->prev) { ip->live = live; ! ! for (reg = FIRSTREG; reg <= LASTREG ;reg++) { ! if (ip->rref & RM(reg)) ! live |= RM(reg); ! else if (ip->rset & RM(reg)) ! live &= ~RM(reg); ! } } } --- 162,169 ---- */ for (ip = bp->last; ip != NULL ;ip = ip->prev) { ip->live = live; ! live |= ip->rref; ! live &= ip->rref | ~ip->rset; } } SHAR_EOF fi if test -f 'main.dif' then echo shar: "will not over-write existing file 'main.dif'" else cat << \SHAR_EOF > 'main.dif' *** top1.2/main.c Fri Aug 24 17:07:19 1990 --- main.c Tue Oct 2 10:15:14 1990 *************** *** 7,13 **** --- 7,16 ---- * 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. + * + * Modified by Tohru Nishimura, Software Research Associates, Tokyo, Oct 1990. */ + #include "top.h" FILE *ifp, *ofp; /* input/output file pointers */ *************** *** 43,49 **** int use_temp = FALSE; /* using temporary file */ char *Version = ! "top Version 1.20 Copyright (c) 1988,1989 by Sozobon, Limited."; usage() { --- 46,52 ---- int use_temp = FALSE; /* using temporary file */ char *Version = ! "top Version 1.2x Copyright (c) 1988,1989 by Sozobon, Limited."; usage() { SHAR_EOF fi exit 0 # End of shell archive