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