This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
gcc 2.95.3 optimization bug
- From: David Taylor <dtaylor at emc dot com>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Tue, 18 Nov 2003 09:55:41 -0500
- Subject: gcc 2.95.3 optimization bug
[I realize that there will be no more 2.x releases of GCC -- and that
therefore this bug fix will not appear in a release. But, there are
people still using GCC 2.x. EMC still uses 2.x (yes, we are migrating
to 3.x -- but, we will -- for some time -- care about 2.x for previous
releases of our product).]
The following problem was observed in a 2.95.3 x86 x powerpc-elf-eabi
GCC, though it is not powerpc specific.
Consider the following simple function (reduced from something much larger):
int func (int x)
{
int y = 0;
switch (x)
{
case 6: { y = 3; break; }
case 7: { y = 4; break; }
case 10: { y = 6; break; }
case 11: { y = 7; break; }
case 12: { y = 8; break; }
}
return (0);
}
During the 5th (and final) call to jump_optimize_1, we have RTL that looks somewhat like:
notes and insns (some deleted, some not)
jump to code label 72 -- conditional
notes and deleted insns
jump to code label 72 -- unconditional
note
barrier
code label 72 -- use count 2
set return register to 0
return
The code examines the first jump; decides it can delete it since it's
followed by an unconditional jump to same place and there are no
active instructions between the two. Decrements the use count of
label 72. All fine.
Then it examines the second jump; decides it can delete it since by
falling through and by jumping it ends up in the same place. Fine.
It deletes the jump. Fine. It updates the use count of label 72.
All fine. *BUT* it fails to delete the barrier because of the
intervening note. Oops!
Then it examines the label -- now with a use count of 0 -- decides it
can delete it. Fine. Notices the barrier right before it (!!!!!);
decides that this is dead code and that it should delete forward until
the next label (or end of function). Major OOPS -- this isn't dead
code.
Result: not only is the function return value not set, it doesn't
generate the return jump (in the powerpc case -- the blr instruction)
-- so it ends up falling into the next function in the executable.
The fix is to scan for the next instruction and notice the barrier.
Here's a context diff to delete_insn in jump.c:
Index: jump.c
===================================================================
RCS file: /emc/ucode/cvsroot_0/gcc-2.95.3/gcc/jump.c,v
retrieving revision 1.2
diff -c -r1.2 jump.c
*** jump.c 3 Mar 2003 16:58:39 -0000 1.2
--- jump.c 18 Nov 2003 14:22:51 -0000
***************
*** 4026,4031 ****
--- 4026,4041 ----
INSN_DELETED_P (next) = 1;
next = NEXT_INSN (next);
}
+ else if (next != 0 && GET_CODE (next) == NOTE)
+ {
+ /* the next *REAL* instruction might be a barrier -- a barrier
+ that should be deleted because the unconditional jump before
+ it is now gone. */
+ rtx next2 = next_nonnote_insn (next);
+
+ if (next2 && (GET_CODE (next2) == BARRIER))
+ delete_insn (next2);
+ }
/* Patch out INSN (and the barrier if any) */