donn@wasatch.UUCP (Donn Seeley) (03/10/89)
In a certain very odd set of circumstances, gcc 1.34 can drop an
increment or decrement operation. In our case, we discovered that rrn
would loop decrementing a count without incrementing a character
pointer; when the count is exhausted without finding a null byte in the
string, rrn aborts. Here's a simplified example; comments in the
assembly listing indicate where the problem lies:
------------------------------------------------------------------------
Script started on Thu Mar 9 13:02:46 1989
% cat i2.c
/*
* Stimulate the increment/decrement bug.
*
* The increment/decrement must live under a MEM.
* The operand of the i/d must be a pseudo-register that doesn't get
* assigned a hard register in local or global allocation.
* Going left to right through the RTL for an expression, the i/d must
* be followed by an instance of the i/d operand without i/d.
*/
x(ipppp, xp)
int ****ipppp, *xp;
{
int ***ippp, **ipp, *ip, i;
while (ippp = *ipppp++) {
while (ipp = *ippp++)
while (ip = *ipp++)
while (i = *ip++)
y(i, ip, ipp, ippp, ipppp);
*xp++ |= i;
}
}
% cc -v -S -O -B./old- i2.c
gcc version 1.34
/usr/local/lib/gcc-cpp -nostdinc -v -I/usr/include -undef -D__GNUC__ -Dmc68000 -Dhp300 -Dunix -D__mc68000__ -D__hp300__ -D__unix__ -D__OPTIMIZE__ -traditional -D__HAVE_FPU__ i2.c /tmp/cc012799.cpp
GNU CPP version 1.34
./old-cc1 /tmp/cc012799.cpp -quiet -dumpbase i2.c -O -traditional -fwritable-strings -fno-defer-pop -version -o i2.s
GNU C version 1.34 (68k, MIT syntax) compiled by GNU C version 1.34.
% cat i2.s
#NO_APP
gcc_compiled.:
.text
.even
.globl _x
_x:
link a6,#-4
moveml #0x3c,sp@-
movel a6@(8),a5
movel a6@(12),a6@(-4)
jra L2
L10:
movel a5,sp@-
movel a4,sp@-
movel a3,sp@-
movel a2,sp@-
movel d0,sp@-
jbsr _y
addw #20,sp
L8:
movel a2@+,d0
jne L10
L6:
movel a3@+,a2
tstl a2
jne L8
L4:
movel a4@+,a3
tstl a3
jne L6
movel a6@(-4),a0 /* xp never gets incremented */
orl d0,a0@
L2:
movel a5@+,a4
tstl a4
jne L4
moveml a6@(-20),#0x3c00
unlk a6
rts
%
------------------------------------------------------------------------
A study of the RTL for the example will show that the post-increment
disappears during reloading. Here's what the RTL looks like prior to
reloading for the insn that contains the problematic increment:
(insn 61 60 62 (set (mem:SI (post_inc:SI (reg/v:SI 57)))
(ior:SI (reg/v:SI 61)
(mem:SI (reg/v:SI 57)))) 137 (insn_list 59 (nil))
(expr_list:HI (reg/v:SI 57)
(nil)))
There are insufficiently many address registers to hold all the
pointers, so the variable 'xp' ends up without one and it has to be
reloaded. The function find_reloads_address_1() is responsible for
taking care of side effects from increment and decrement operations
under a MEM when the operand of the increment or decrement is a
pseudo-register that needs to be reloaded; in this example, it must
handle (post_inc:SI (reg/v:SI 57)). It calls push_reload() to schedule
the adjustments and reloading; push_reload() tucks away a copy of the
operand in the reload_in array. Later, when push_reload() is called
for (reg/v:SI 57) without the post_inc, it correctly matches this with
the reload for the increment/decrement but clobbers the copy of the
operand in reload_in. Still later, in choose_reload_targets(), the
inc_for_reload() function never gets called if the reload_in entry
doesn't contain an increment or decrement, and as a result the
operation gets lost.
The cheap way of solving the problem is to prevent push_reload() from
clobbering reload_in if the matching operand doesn't have an increment
or decrement; here's what I did:
------------------------------------------------------------------------
*** /tmp/,RCSt1012836 Thu Mar 9 13:07:59 1989
--- reload.c Thu Mar 9 13:06:21 1989
***************
*** 380,386 ****
reload_inmode[i] = inmode;
if (outmode != VOIDmode)
reload_outmode[i] = outmode;
! if (in != 0)
reload_in[i] = in;
if (out != 0)
reload_out[i] = out;
--- 380,386 ----
reload_inmode[i] = inmode;
if (outmode != VOIDmode)
reload_outmode[i] = outmode;
! if (in != 0 && GET_CODE (in) != REG)
reload_in[i] = in;
if (out != 0)
reload_out[i] = out;
------------------------------------------------------------------------
The assembly code for the example turns into the following:
------------------------------------------------------------------------
% cc -v -S -O i2.c
gcc version 1.34
/usr/local/lib/gcc-cpp -nostdinc -v -I/usr/include -undef -D__GNUC__ -Dmc68000 -Dhp300 -Dunix -D__mc68000__ -D__hp300__ -D__unix__ -D__OPTIMIZE__ -traditional -D__HAVE_FPU__ i2.c /tmp/cc012803.cpp
GNU CPP version 1.34
/usr/local/lib/gcc-cc1 /tmp/cc012803.cpp -quiet -dumpbase i2.c -O -traditional -fwritable-strings -fno-defer-pop -version -o i2.s
GNU C version 1.34 (68k, MIT syntax) compiled by GNU C version 1.34.
% cat i2.s
#NO_APP
gcc_compiled.:
.text
.even
.globl _x
_x:
link a6,#-4
moveml #0x3c,sp@-
movel a6@(8),a5
movel a6@(12),a6@(-4)
jra L2
L10:
movel a5,sp@-
movel a4,sp@-
movel a3,sp@-
movel a2,sp@-
movel d0,sp@-
jbsr _y
addw #20,sp
L8:
movel a2@+,d0
jne L10
L6:
movel a3@+,a2
tstl a2
jne L8
L4:
movel a4@+,a3
tstl a3
jne L6
movel a6@(-4),a0
addqw #4,a0 /* increment ... */
movel a0,a6@(-4) /* ... and update xp */
subql #4,a0
orl d0,a0@
L2:
movel a5@+,a4
tstl a4
jne L4
moveml a6@(-20),#0x3c00
unlk a6
rts
% exit
script done on Thu Mar 9 13:03:36 1989
------------------------------------------------------------------------
Rrn works now, and regressions didn't turn up any code changes except
for the one in rrn....
Donn Seeley University of Utah CS Dept donn@cs.utah.edu
40 46' 6"N 111 50' 34"W (801) 581-5668 utah-cs!donn