home *** CD-ROM | disk | FTP | other *** search
- /* 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.
- */
-
- /*
- * 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 INST *ti2; /* "temporary" next inst */
-
- register int op1, op2; /* opcodes, for speed */
- register int sm1, dm1; /* src, dst amode inst. 1 */
- register int dr1; /* dest. reg. inst. 1 */
-
- i2 = i1->next;
- op1 = i1->opcode;
- op2 = i2->opcode;
-
- sm1 = i1->src.amode;
- dm1 = i1->dst.amode;
- dr1 = i1->dst.areg;
-
- /*
- * Avoid stack fix-ups after a call if possible.
- */
-
- /*
- * addq #4,sp
- * ... stuff that doesn't use SP ...
- * move.l ?,-(sp) => move.l ?,(sp)
- */
- if (op1 == ADDQ && sm1 == IMM && i1->src.disp == 4 &&
- dm1 == REG && dr1 == SP) {
-
- ti2 = i2;
- while (!uses(ti2, SP)) {
- if (ti2->next == NULL)
- goto end2;
- ti2 = ti2->next;
- }
-
- if (ti2->opcode == MOVE && ti2->flags == LENL &&
- ti2->dst.amode == (REGI|DEC) && ti2->dst.areg == SP) {
- ti2->dst.amode = REGI;
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
- end2:
-
- /*
- * addq #2,sp
- * ... stuff that doesn't use SP ...
- * move.w ?,-(sp) => move.w ?,(sp)
- */
- if (op1 == ADDQ && sm1 == IMM && i1->src.disp == 2 &&
- dm1 == REG && dr1 == SP) {
-
- ti2 = i2;
- while (!uses(ti2, SP)) {
- if (ti2->next == NULL)
- goto end3;
- ti2 = ti2->next;
- }
-
- if (ti2->opcode == MOVE && ti2->flags == LENW &&
- ti2->dst.amode == (REGI|DEC) && ti2->dst.areg == SP) {
- ti2->dst.amode = REGI;
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
- end3:
-
- /*
- * 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.
- */
- if (bp->last == i2 && (bp->bcode == BEQ || bp->bcode == BNE) &&
- op1 == MOVE && op2 == TST &&
- i1->flags == i2->flags) {
-
- /*
- * If pre-decrement is set on the dest. of the move,
- * don't let that screw up the operand comparison.
- */
- if (dm1 & DEC)
- dm1 &= ~DEC;
-
- if (opeq(&i1->dst, &i2->src) || opeq(&i1->src, &i2->src)) {
- if (dm1 != REG || ISD(dr1)) {
- delinst(bp, i2);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
- }
-
- /*
- * and.x X, Y => and.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.
- */
- if (bp->last == i2 && (bp->bcode == BEQ || bp->bcode == BNE) &&
- op1 == AND && op2 == TST &&
- i1->flags == i2->flags) {
-
- /*
- * If pre-decrement is set on the dest. of the move,
- * don't let that screw up the operand comparison.
- */
- if (dm1 & DEC)
- dm1 &= ~DEC;
-
- if (opeq(&i1->dst, &i2->src) || opeq(&i1->src, &i2->src)) {
- if (dm1 != REG || ISD(dr1)) {
- delinst(bp, i2);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
- }
-
- /*
- * ext.x Dn => ext.x Dn
- * tst.x Dn ...deleted...
- * beq/bne beq/bne
- *
- * Where Y is not An, because "movea" doesn't set the
- * zero flag.
- */
- if (bp->last == i2 && (bp->bcode == BEQ || bp->bcode == BNE) &&
- op1 == EXT && op2 == TST &&
- i1->flags == i2->flags) {
-
- if (sm1 == REG && ISD(i1->src.areg) &&
- i2->src.amode == REG && i1->src.areg == i2->src.areg) {
- delinst(bp, i2);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * move.? X, Dn => move.? X, Dn
- * ext.? 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) {
-
- if (dm1 == REG && ISD(dr1) &&
- i2->src.amode == REG && dr1 == i2->src.areg) {
- if ((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 & LENL) != 0) && ((i2->flags & LENL) != 0) &&
- (i1->src.areg == i2->src.areg) && ISD(i1->src.areg)) {
-
- if ((i2->live & RM(i2->src.areg)) == 0) {
- i2->flags = LENW;
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * ext.l Dm => ...deleted...
- * ??? N(An,Dm.l), ?? ??? N(An,Dm.w), ??
- *
- * Where Dm is dead
- */
- if ((op1 == EXT) && (i1->flags & LENL) &&
- (i2->src.amode == (REGIDX|XLONG)) &&
- (i1->src.areg == i2->src.ireg)) {
-
- if ((i2->live & RM(i1->src.areg)) == 0) {
- i2->src.amode &= ~XLONG;
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * ext.l Dm => ...deleted...
- * ??? ??, N(An,Dm.l) ??? ??, N(An,Dm.w)
- *
- * Where Dm is dead
- */
- if ((op1 == EXT) && (i1->flags & LENL) &&
- (i2->dst.amode == (REGIDX|XLONG)) &&
- (i1->src.areg == i2->dst.ireg)) {
-
- if ((i2->live & RM(i1->src.areg)) == 0) {
- i2->dst.amode &= ~XLONG;
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * Avoid intermediate registers.
- */
-
- /*
- * move.x X, Dm => INST.x X, Dn
- * INST.x Dm, Dn
- *
- * 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) &&
- (dm1 == REG) && ISD(dr1) &&
- (i2->src.amode == REG) && ISD(i2->src.areg) &&
- (dr1 == i2->src.areg) &&
- (i2->dst.amode == REG) && ISD(i2->dst.areg)) {
-
- if ((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
- */
- if ((op1 == MOVE) && (op2 == MOVE) &&
- (i1->flags == i2->flags) &&
- opeq(&i1->src, &i2->dst) && opeq(&i1->dst, &i2->src) &&
- ((i1->src.amode & (INC|DEC)) == 0) &&
- ((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 isn't register direct
- */
- if ((op1 == MOVE) && (op2 == MOVE) && (i2->dst.amode == REG) &&
- opeq(&i1->dst, &i2->src) && ((i1->dst.amode & (INC|DEC)) == 0) &&
- (i1->flags == i2->flags) && (i1->dst.amode != REG) &&
- !uses(i1, i2->dst.areg)) {
-
- freeop(&i1->dst);
- i1->dst = i2->dst;
- i2->dst = i2->src;
- i2->src = i1->dst;
-
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
-
- /*
- * move.x Dm, X => move.x Dm, X
- * move.x X, Y move.x Dm, Y
- *
- * Where 'x' is the same, and 'X' has no side-effects.
- */
- if ((op1 == MOVE) && (op2 == MOVE) &&
- (sm1 == REG) && ISD(i1->src.areg) &&
- (i1->flags == i2->flags) && opeq(&i1->dst, &i2->src) &&
- ((dm1 & (DEC|INC)) == 0)) {
-
-
- freeop(&i2->src);
- i2->src = i1->src;
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
-
- /*
- * move.? Rm, Rn => move.? Rm, Rn
- * ... stuff ... ... stuff ...
- * move.? Rm, Rn
- *
- * where "stuff" doesn't set Rm or 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) && (sm1 == REG) && (dm1 == REG)) {
- int s1 = i1->src.areg; /* source reg of inst. 1 */
-
- ti2 = i2;
- while (ti2 != NULL && !sets(ti2, s1) && !sets(ti2, dr1)) {
-
- if ((ti2->opcode==MOVE) && (i1->flags==ti2->flags) &&
- (ti2->src.amode==REG) && (ti2->dst.amode==REG) &&
- (i1->src.areg == ti2->src.areg) &&
- (i1->dst.areg == ti2->dst.areg) &&
- ((bp->last != ti2) || (bp->bcond == NULL)) ) {
-
- delinst(bp, ti2);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- ti2 = ti2->next;
- }
- }
-
- /*
- * move.l Am, Dn => move.l Am, Ao
- * ... stuff ... ... stuff ...
- * move.l Dn, Ao
- *
- * where "stuff" doesn't set Dn.
- */
- if ((op1 == MOVE) && (i1->flags == LENL) &&
- (sm1 == REG) && ISA(i1->src.areg) &&
- (dm1 == REG) && ISD(dr1)) {
-
- ti2 = i2;
- while (!sets(ti2, dr1)) {
-
- if ((ti2->opcode == MOVE) && (ti2->flags == LENL) &&
- (ti2->src.amode == REG) && ISD(ti2->src.areg) &&
- (ti2->dst.amode == REG) && ISA(ti2->dst.areg) &&
- (dr1 == ti2->src.areg)) {
-
- /*
- * If the intermediate register isn't dead,
- * then we have to keep using it.
- */
- if ((ti2->live & RM(ti2->src.areg)) != 0)
- goto end14;
-
- i1->dst.areg = ti2->dst.areg;
-
- delinst(bp, ti2);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
-
- if (ti2->next == NULL)
- goto end14;
-
- ti2 = ti2->next;
- }
- }
- end14:
-
- /*
- * move.l Dm, An => move.l Dm, Ao
- * lea (An), Ao
- *
- * where An is dead
- */
- if ((op1 == MOVE) && (op2 == LEA) &&
- (sm1 == REG) && ISD(i1->src.areg) &&
- (dm1 == REG) && ISA(dr1) &&
- (i2->src.amode == REGI) && (i2->dst.amode == REG) &&
- ISA(i2->dst.areg) && (dr1 == i2->src.areg)) {
-
- if ((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 => lea X, Ao
- * lea (An), Ao
- *
- * where An is dead
- */
- if ((op1 == LEA) && (op2 == LEA) &&
- (i2->src.amode == REGI) && (dr1 == i2->src.areg)) {
-
- if ((i2->live & RM(i2->src.areg)) == 0) {
-
- i1->dst.areg = i2->dst.areg;
-
- delinst(bp, i2);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * lea N(Am), Am =>
- * ? (Am)[,...] ? N(Am)[,...]
- *
- * Where Am is either dead after the second instruction or
- * is a direct destination of the second instruction.
- */
- if ((op1 == LEA) && (i1->src.amode == REGID) &&
- (i1->src.areg == i1->dst.areg) &&
- (i2->src.amode == REGI) && (i1->dst.areg == i2->src.areg)) {
-
- if (((i2->live & RM(i2->src.areg)) == 0) ||
- ((i2->dst.amode == REG) && (i2->dst.areg == i2->src.areg))) {
- i2->src.amode = REGID;
- i2->src.disp = i1->src.disp;
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * lea N(Am), Am =>
- * ? X, (Am) ? X, N(Am)
- *
- * Where X doesn't reference Am, and Am is dead after the
- * second instruction.
- */
- if ((op1 == LEA) && (i1->src.amode == REGID) &&
- (i1->src.areg == i1->dst.areg) &&
- (i2->dst.amode == REGI) && (i1->dst.areg == i2->dst.areg)) {
-
- if (((i2->live & RM(i2->dst.areg)) == 0) &&
- ((i2->src.amode == IMM) || (i2->src.amode == ABS) ||
- (i2->src.areg != i2->dst.areg))) {
- i2->dst.amode = REGID;
- i2->dst.disp = i1->src.disp;
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * lea X, Am => ...deleted...
- * clr.x (Am) clr.x X
- *
- * where Am is dead
- */
- if ((op1 == LEA) && (op2 == CLR) && i2->src.amode == REGI &&
- (i1->dst.areg == i2->src.areg)) {
-
- if ((i2->live & RM(i2->src.areg)) == 0) {
- i2->src = i1->src;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * lea X, Am => ...deleted...
- * move.x Y, (Am) move.x Y, X
- *
- * where Am is dead
- */
- if ((op1 == LEA) && (op2 == MOVE) && i2->dst.amode == REGI &&
- (i1->dst.areg == i2->dst.areg)) {
-
- if ((i2->live & RM(i2->dst.areg)) == 0) {
- i2->dst = i1->src;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * lea X, Am => ...deleted...
- * move.x (Am), Y move.x X, Y
- *
- * where Am is dead
- */
- if ((op1 == LEA) && (op2 == MOVE) && i2->src.amode == REGI &&
- (i1->dst.areg == i2->src.areg)) {
-
- if ((i2->live & RM(i2->src.areg)) == 0) {
- i2->src = i1->src;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * move.x Dm, X => move.x Dm, X
- * cmp.x #N, X cmp.x #N, Dm
- *
- * Where X isn't register direct.
- *
- * Since X generally references memory, we can compare
- * with the register faster.
- */
- if ((op1 == MOVE) && (op2 == CMP) &&
- (i1->flags == i2->flags) && (i2->src.amode == IMM) &&
- (sm1 == REG) && ISD(i1->src.areg) && (dm1 != REG) &&
- opeq(&i1->dst, &i2->dst) && ((dm1 & (INC|DEC)) == 0)) {
-
- freeop(&i2->dst);
- i2->dst.amode = REG;
- i2->dst.areg = i1->src.areg;
-
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
-
-
- /*
- * Try to use register indirect w/ displacement and/or index
- */
-
- /*
- * add.l Am, Dn => lea 0(Am,Dn.l), Ao
- * move.l Dn, Ao
- *
- * where Dn is dead
- */
- if ((op1 == ADD) && (op2 == MOVE) &&
- (sm1 == REG) && ISA(i1->src.areg) &&
- (dm1 == REG) && ISD(dr1) &&
- (i2->src.amode == REG) && ISD(i2->src.areg) &&
- (i2->dst.amode == REG) && ISA(i2->dst.areg) &&
- (dr1 == i2->src.areg) &&
- (i1->flags & LENL) && (i2->flags & LENL)) {
-
- if ((i2->live & RM(i2->src.areg)) == 0) {
-
- i2->opcode = LEA;
- i2->flags = 0;
-
- i2->src.amode = REGIDX|XLONG;
- i2->src.disp = 0;
- i2->src.areg = i1->src.areg;
- i2->src.ireg = dr1;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * add.l Dm, An => move.x 0(An,Dm.l), Do
- * move.x (An), Do
- *
- * where An is dead
- */
- if ((op1 == ADD) && (op2 == MOVE) &&
- (sm1 == REG) && ISD(i1->src.areg) &&
- (dm1 == REG) && ISA(dr1) &&
- (i2->src.amode == REGI)&& ISA(i2->src.areg) &&
- (i2->dst.amode == REG) && ISD(i2->dst.areg) &&
- (dr1 == i2->src.areg) && (i1->flags & LENL)) {
-
- if ((i2->live & RM(i2->src.areg)) == 0) {
-
- i2->src.amode = REGIDX|XLONG;
- i2->src.disp = 0;
- i2->src.ireg = i1->src.areg;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- }
-
- /*
- * lea N(Am), An => lea N(Am,Do.l), An
- * add.l Do, An
- *
- */
- if ((op1 == LEA) && (op2 == ADD) &&
- (sm1 == REGID) &&
- (i2->src.amode == REG) && ISD(i2->src.areg) &&
- (i2->dst.amode == REG) && ISA(i2->dst.areg) &&
- (dr1 == i2->dst.areg) && D8OK(i1->src.disp)) {
-
- i1->src.amode = REGIDX|XLONG;
- i1->src.ireg = i2->src.areg;
- delinst(bp, i2);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
-
-
-
- /*
- * Try to use the pre-decrement and post-increment modes
- * whenever possible.
- */
-
- /*
- * sub.l #1, Am
- * ... stuff ...
- * ???.b ..(Am).. => ???.b ..-(Am)..
- *
- * Nothing in "stuff" can refer to Am.
- */
- if ((op1 == SUB) && (i1->flags & LENL) &&
- (sm1 == IMM) && (i1->src.disp == 1) &&
- (dm1 == REG) && ISA(dr1)) {
-
- while (i2 != NULL) {
-
- if (i2->src.amode == REGI && i2->src.areg == dr1) {
-
- if ((i2->flags & LENB) == 0)
- goto end24;
-
- i2->src.amode |= DEC;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- if (i2->dst.amode == REGI && i2->dst.areg == dr1) {
-
- if ((i2->flags & LENB) == 0)
- goto end24;
-
- i2->dst.amode |= DEC;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- if (uses(i2, dr1))
- goto end24;
-
- if (i2->next == NULL)
- goto end24;
- else
- i2 = i2->next;
-
- }
- }
- end24:
-
- /*
- * sub.l #2, Am
- * ... stuff ...
- * ???.w ..(Am).. => ???.w ..-(Am)..
- *
- * Nothing in "stuff" can refer to Am.
- */
- if ((op1 == SUB) && (i1->flags & LENL) &&
- (sm1 == IMM) && (i1->src.disp == 2) &&
- (dm1 == REG) && ISA(dr1)) {
-
- while (i2 != NULL) {
-
- if (i2->src.amode == REGI && i2->src.areg == dr1) {
-
- if ((i2->flags & LENW) == 0)
- goto end26;
-
- i2->src.amode |= DEC;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- if (i2->dst.amode == REGI && i2->dst.areg == dr1) {
-
- if ((i2->flags & LENW) == 0)
- goto end26;
-
- i2->dst.amode |= DEC;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
-
- if (uses(i2, dr1))
- goto end26;
-
- if (i2->next == NULL)
- goto end26;
- else
- i2 = i2->next;
-
- }
- }
- end26:
-
- /*
- * sub.l #4, Am
- * ... stuff ...
- * ???.l ..(Am).. => ???.l ..-(Am)..
- *
- * Nothing in "stuff" can refer to Am.
- */
- if ((op1 == SUB) && (i1->flags & LENL) &&
- (sm1 == IMM) && (i1->src.disp == 4) &&
- (dm1 == REG) && ISA(dr1)) {
-
- while (i2 != NULL) {
-
- if (i2->src.amode == REGI && i2->src.areg == dr1) {
-
- if ((i2->flags & LENL) == 0)
- goto end28;
-
- i2->src.amode |= DEC;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
- if (i2->dst.amode == REGI && i2->dst.areg == dr1) {
-
- if ((i2->flags & LENL) == 0)
- goto end28;
-
- i2->dst.amode |= DEC;
-
- delinst(bp, i1);
- DBG(printf("%d ", __LINE__))
- return TRUE;
- }
-
- if (uses(i2, dr1))
- goto end28;
-
- if (i2->next == NULL)
- goto end28;
- else
- i2 = i2->next;
-
- }
- }
- end28:
-
- 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 :"))
-
- for (; bp != NULL ;bp = bp->next) {
- for (ip = bp->first; 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;
- } else
- ip = ip->next;
- }
- }
- DBG(printf("\n"); fflush(stdout))
- return changed;
- }
-