Path: meolyon!mwhh!news.Hanse.DE!news.rrz.uni-hamburg.de!news.dkrz.de!news.tu-harburg.de!news.dfn.de!Germany.EU.net!EU.net!news.sprintlink.net!tank.news.pipex.net!pipex!news.mathworks.com!panix!bloom-beacon.mit.edu!usc!math.ohio-state.edu!magnus.acs.ohio-state.edu!cis.ohio-state.edu!meolyon.hanse.DE!amylaar From: amylaar@meolyon.hanse.DE (Joern Rennecke) Newsgroups: gnu.gcc.bug Subject: REG_EQUIV confusion (Was: gcc 2.7.0 bug HP-PA) Date: 5 Sep 1995 00:37:11 -0400 Organization: GNUs Not Usenet Lines: 99 Sender: daemon@cis.ohio-state.edu Approved: bug-gcc@prep.ai.mit.edu Distribution: gnu Message-ID: <m0spomo-000D1tC@meolyon> ~Newsgroups: gnu.gcc.bug Path: amylaar ~From: amylaar@meolyon.hanse.de (Joern Rennecke) ~Subject: REG_EQUIV confusion (Was: gcc 2.7.0 bug HP-PA) Distribution: gnu Organization: Private site running Linux Message-ID: <1995Sep5.033452.1390@meolyon.hanse.de> ~References: <DD1EzG.D1L@ida.liu.se> ~Date: Tue, 5 Sep 1995 03:34:52 GMT mpe@ida.liu.se (Mikael Pettersson) writes: >GCC 2.7.0 and 2.6.3, configured with "i486-hp-solaris2", >grossly miscompile (with -O1) the following function: > >/* yyy.c */ >struct rml_state { > void **SP, *FC, **SC, *TP, *ARGS[10]; >}; >extern void *Unify_2eunify(struct rml_state*); >extern void *sclam616(struct rml_state*); > >void *sclam617(struct rml_state *rmlState) >{ > void **tmp950 = rmlState->SC; > void *tmp375 = tmp950[1]; /*1a*/ > void *tmp374 = tmp950[2]; > void *tmp602 = tmp950[3]; > void *tmp609 = rmlState->ARGS[0]; > void *tmp610 = rmlState->ARGS[1]; /*2a*/ > tmp950[3] = tmp375; /*1b*/ > tmp950[2] = tmp602; > tmp950[1] = tmp610; /*2b*/ > tmp950[0] = (void*)sclam616; > rmlState->ARGS[1] = tmp609; > rmlState->ARGS[0] = tmp602; > rmlState->FC = (void**)tmp374; > rmlState->SP = tmp950; > return (void*)Unify_2eunify; >} > >The problem is that gcc performs the second load-store group >(2a and 2b) BEFORE it does the load at 1a, and in doing so >overwrites the original value of tmp950[1]. tmp375 will then >later be loaded with the wrong value. I used some rtl dumps and gdb to find out where the problem occurs. It seems to be due to a definition problem what REG_EQUIV really is. rtl.texi states: For @code{REG_EQUIV}, the register is equivalent to @var{op} throughout the entire function, and could validly be replaced in all its occurrences by @var{op}. (``Validly'' here refers to the data flow of the program; simple replacement may make some insns invalid.) For example, when a constant is loaded into a register that is never assigned any other value, this kind of note is used. OTOH, update_equiv_regs () in "local-alloc.c" seems to have a different idea what REG_EQUIV might be validly used for. Here is the relevant section from the code: /* If this insn introduces a "constant" register, decrease the priority of that register. Record this insn if the register is only used once more and the equivalence value is the same as our source. The latter condition is checked for two reasons: First, it is an indication that it may be more efficient to actually emit the insn as written (if no registers are available, reload will substitute the equivalence). Secondly, it avoids problems with any registers dying in this insn whose death notes would be missed. If we don't have a REG_EQUIV note, see if this insn is loading a register used only in one basic block from a MEM. If so, and the MEM remains unchanged for the life of the register, add a REG_EQUIV note. */ note = find_reg_note (insn, REG_EQUIV, NULL_RTX); if (note == 0 && reg_basic_block[regno] >= 0 && GET_CODE (SET_SRC (set)) == MEM && validate_equiv_mem (insn, dest, SET_SRC (set))) REG_NOTES (insn) = note = gen_rtx (EXPR_LIST, REG_EQUIV, SET_SRC (set), REG_NOTES (insn)); Now this causes problems when the instructions get reordered later in a way that expands the lifetime of the register so that it overlaps with a point in time when the MEM has a different value. Thus, REG_EQUIV is usually used as meaning 'equal in the entire scope of the register' while equiv_regs() uses it to denote 'equal in the entire lifetime of the register' , which is unfortunately not quite the same. What is the correct definition of REG_EQUIV? And should there be an additional note type to describe the situation that is currently described wrongly as REG_EQUIV ? Joern Rennecke Path: meolyon!mwhh!news.Hanse.DE!news.rrz.uni-hamburg.de!news.dkrz.de!news.tu-harburg.de!news.dfn.de!Germany.EU.net!EU.net!howland.reston.ans.net!math.ohio-state.edu!magnus.acs.ohio-state.edu!cis.ohio-state.edu!meolyon.hanse.DE!amylaar From: amylaar@meolyon.hanse.DE (Joern Rennecke) Newsgroups: gnu.gcc.bug Subject: Re: More on the -fforce-mem optimization bug on i386 Date: 8 Sep 1995 23:37:51 -0400 Organization: GNUs Not Usenet Lines: 113 Sender: daemon@cis.ohio-state.edu Approved: bug-gcc@prep.ai.mit.edu Distribution: gnu Message-ID: <m0srFCU-000DfMC@meolyon> ~Newsgroups: gnu.gcc.bug Path: amylaar ~From: amylaar@meolyon.hanse.de (Joern Rennecke) ~Subject: Re: More on the -fforce-mem optimization bug on i386 Distribution: gnu Organization: Private site running Linux Message-ID: <1995Sep9.015918.1154@meolyon.hanse.de> ~References: <9508280955.AA14222@crunch> ~Date: Sat, 9 Sep 1995 01:59:18 GMT anlauf@crunch.ikp.physik.th-darmstadt.de (Harald Anlauf) writes: >Hi, >last weekend I did some more research on the -fforce-mem problem on i386 >platforms reported by me. It appears that it is the declaration of >static variables that confuses gcc. See below a stripped-down C version >of a subset of the original program: >Test run output, when compiled with gcc 2.5.8 and gcc 2.7.0 >(i486-*-linuxoldld): >gcc -O1 -fno-force-mem: > 12 34 56 78 > 16 32 110 89 110 > 48 28 116 139 116 >(which is correct). >gcc -O1 -fforce-mem: > 12 34 56 78 > 115 115 134 89 134 > 50 50 115 139 115 >(which is wrong). >Replacing -O1 by -O2 seems to "fix" the problem for the stripped-down >program as appended below, but this is misleading, since the full >program in the original report still exhibits the bug (because there are >even more static variables declared ... ;-) >Note that in the translation of Fortran77 to C by f2c local variables >are defined as static, so I would be interested to know if the original >Fortran program works correctly with g77. Could somebody please test >this, with the appropriate flags? >Cheers, >Harald >bug.c: >------------------------------> cut here <------------------------------ >void bug(void) >{ > int i, l, m, ii, jj; > static int j, k; >/* If I change any of j, k to automatic, gcc -fforce-mem -O will compile > the code correctly !?!?!?!? */ > i = 12; > j = 34; > k = 56; > l = 78; > printf ("%9d %9d %9d %9d\n", i, j, k, l); > for (ii = 1; ii <= 2; ++ii) { > for (jj = 1; jj <= 24; ++jj) { > m = i * j % 179 * k % 179; > i = j; > j = k; > k = m; > l = (l * 53 + 1) % 169; > } > printf ("%9d %9d %9d %9d %9d\n", i, j, k, l, m); > } >} /* bug */ >main() >{ > bug (); > exit (0); >} /* main */ >------------------------------> cut here <------------------------------ This bug seems to be due to the REG_EQUIV confusion too. At least it goes away when the appended patch is applied. Joern Rennecke *** gcc-2.7.0/local-alloc.c Sat Jul 8 01:56:38 1995 --- gcc-2.7.0-x/local-alloc.c Tue Sep 5 06:02:58 1995 *************** update_equiv_regs () *** 987,992 **** --- 987,996 ---- insn that set REG is safe. If so, put a REG_EQUIV note on the initializing insn. */ + #if 0 + /* This is invalid when code gets reordered. Therefore, I temporarily + * disabled this code. Joern Rennecke Tue Sep 5 06:02:24 MET DST 1995 + */ if (GET_CODE (dest) == MEM && GET_CODE (SET_SRC (set)) == REG && (regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER && reg_basic_block[regno] >= 0 *************** update_equiv_regs () *** 998,1003 **** --- 1002,1008 ---- REG_NOTES (reg_equiv_init_insn[regno]) = gen_rtx (EXPR_LIST, REG_EQUIV, dest, REG_NOTES (reg_equiv_init_insn[regno])); + #endif /* If this is a register-register copy where SRC is not dead, see if we can optimize it. */